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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/avi/AVI_avi.h7
-rw-r--r--source/blender/avi/intern/avi_mjpeg.c43
-rw-r--r--source/blender/blenfont/BLF_api.h6
-rw-r--r--source/blender/blenfont/BLF_translation.h5
-rw-r--r--source/blender/blenfont/CMakeLists.txt10
-rw-r--r--source/blender/blenfont/SConscript5
-rw-r--r--source/blender/blenfont/intern/blf_font.c41
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c8
-rw-r--r--source/blender/blenfont/intern/blf_internal.h3
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h4
-rw-r--r--source/blender/blenfont/intern/blf_lang.c13
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c121
-rw-r--r--source/blender/blenfont/intern/blf_translation.c28
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h7
-rw-r--r--source/blender/blenkernel/BKE_action.h12
-rw-r--r--source/blender/blenkernel/BKE_addon.h2
-rw-r--r--source/blender/blenkernel/BKE_anim.h3
-rw-r--r--source/blender/blenkernel/BKE_animsys.h26
-rw-r--r--source/blender/blenkernel/BKE_appdir.h5
-rw-r--r--source/blender/blenkernel/BKE_armature.h54
-rw-r--r--source/blender/blenkernel/BKE_blender.h25
-rw-r--r--source/blender/blenkernel/BKE_bpath.h22
-rw-r--r--source/blender/blenkernel/BKE_brush.h36
-rw-r--r--source/blender/blenkernel/BKE_camera.h39
-rw-r--r--source/blender/blenkernel/BKE_cloth.h4
-rw-r--r--source/blender/blenkernel/BKE_collision.h4
-rw-r--r--source/blender/blenkernel/BKE_colortools.h3
-rw-r--r--source/blender/blenkernel/BKE_constraint.h4
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_curve.h13
-rw-r--r--source/blender/blenkernel/BKE_customdata.h1
-rw-r--r--source/blender/blenkernel/BKE_deform.h1
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h3
-rw-r--r--source/blender/blenkernel/BKE_displist.h5
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h6
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h4
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h1
-rw-r--r--source/blender/blenkernel/BKE_effect.h3
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h10
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h2
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_global.h5
-rw-r--r--source/blender/blenkernel/BKE_group.h2
-rw-r--r--source/blender/blenkernel/BKE_icons.h38
-rw-r--r--source/blender/blenkernel/BKE_idcode.h1
-rw-r--r--source/blender/blenkernel/BKE_image.h56
-rw-r--r--source/blender/blenkernel/BKE_key.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h7
-rw-r--r--source/blender/blenkernel/BKE_library.h5
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_mask.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h11
-rw-r--r--source/blender/blenkernel/BKE_mball_tessellate.h36
-rw-r--r--source/blender/blenkernel/BKE_mesh.h37
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h15
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h3
-rw-r--r--source/blender/blenkernel/BKE_multires.h7
-rw-r--r--source/blender/blenkernel/BKE_nla.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h14
-rw-r--r--source/blender/blenkernel/BKE_object.h64
-rw-r--r--source/blender/blenkernel/BKE_ocean.h26
-rw-r--r--source/blender/blenkernel/BKE_outliner_treehash.h (renamed from source/blender/blenkernel/BKE_treehash.h)19
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h12
-rw-r--r--source/blender/blenkernel/BKE_particle.h14
-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_rigidbody.h16
-rw-r--r--source/blender/blenkernel/BKE_sca.h1
-rw-r--r--source/blender/blenkernel/BKE_scene.h43
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h21
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h1
-rw-r--r--source/blender/blenkernel/BKE_sound.h94
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h4
-rw-r--r--source/blender/blenkernel/BKE_text.h3
-rw-r--r--source/blender/blenkernel/BKE_texture.h70
-rw-r--r--source/blender/blenkernel/BKE_tracking.h18
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h18
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h14
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h15
-rw-r--r--source/blender/blenkernel/CMakeLists.txt17
-rw-r--r--source/blender/blenkernel/SConscript4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c78
-rw-r--r--source/blender/blenkernel/intern/action.c68
-rw-r--r--source/blender/blenkernel/intern/addon.c6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c109
-rw-r--r--source/blender/blenkernel/intern/appdir.c185
-rw-r--r--source/blender/blenkernel/intern/armature.c542
-rw-r--r--source/blender/blenkernel/intern/armature_update.c697
-rw-r--r--source/blender/blenkernel/intern/blender.c42
-rw-r--r--source/blender/blenkernel/intern/bpath.c73
-rw-r--r--source/blender/blenkernel/intern/brush.c44
-rw-r--r--source/blender/blenkernel/intern/camera.c290
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c89
-rw-r--r--source/blender/blenkernel/intern/cloth.c22
-rw-r--r--source/blender/blenkernel/intern/colortools.c196
-rw-r--r--source/blender/blenkernel/intern/constraint.c18
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c8
-rw-r--r--source/blender/blenkernel/intern/curve.c114
-rw-r--r--source/blender/blenkernel/intern/customdata.c8
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c40
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h7
-rw-r--r--source/blender/blenkernel/intern/deform.c10
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c421
-rw-r--r--source/blender/blenkernel/intern/displist.c16
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c31
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c50
-rw-r--r--source/blender/blenkernel/intern/editmesh.c18
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c58
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c20
-rw-r--r--source/blender/blenkernel/intern/freestyle.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c16
-rw-r--r--source/blender/blenkernel/intern/icons.c351
-rw-r--r--source/blender/blenkernel/intern/idcode.c87
-rw-r--r--source/blender/blenkernel/intern/image.c1344
-rw-r--r--source/blender/blenkernel/intern/ipo.c26
-rw-r--r--source/blender/blenkernel/intern/key.c30
-rw-r--r--source/blender/blenkernel/intern/lamp.c4
-rw-r--r--source/blender/blenkernel/intern/lattice.c17
-rw-r--r--source/blender/blenkernel/intern/library.c66
-rw-r--r--source/blender/blenkernel/intern/linestyle.c13
-rw-r--r--source/blender/blenkernel/intern/mask.c11
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c3
-rw-r--r--source/blender/blenkernel/intern/material.c40
-rw-r--r--source/blender/blenkernel/intern/mball.c1935
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c1325
-rw-r--r--source/blender/blenkernel/intern/mesh.c225
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c27
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c78
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c97
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c29
-rw-r--r--source/blender/blenkernel/intern/modifier.c48
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c5
-rw-r--r--source/blender/blenkernel/intern/movieclip.c12
-rw-r--r--source/blender/blenkernel/intern/multires.c52
-rw-r--r--source/blender/blenkernel/intern/nla.c56
-rw-r--r--source/blender/blenkernel/intern/node.c74
-rw-r--r--source/blender/blenkernel/intern/object.c461
-rw-r--r--source/blender/blenkernel/intern/object_deform.c4
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c10
-rw-r--r--source/blender/blenkernel/intern/object_update.c348
-rw-r--r--source/blender/blenkernel/intern/ocean.c48
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c (renamed from source/blender/blenkernel/intern/treehash.c)57
-rw-r--r--source/blender/blenkernel/intern/packedFile.c88
-rw-r--r--source/blender/blenkernel/intern/paint.c69
-rw-r--r--source/blender/blenkernel/intern/particle.c38
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c24
-rw-r--r--source/blender/blenkernel/intern/particle_system.c47
-rw-r--r--source/blender/blenkernel/intern/pbvh.c65
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c732
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h8
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c50
-rw-r--r--source/blender/blenkernel/intern/scene.c627
-rw-r--r--source/blender/blenkernel/intern/screen.c51
-rw-r--r--source/blender/blenkernel/intern/seqcache.c7
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c5
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c28
-rw-r--r--source/blender/blenkernel/intern/sequencer.c1081
-rw-r--r--source/blender/blenkernel/intern/smoke.c11
-rw-r--r--source/blender/blenkernel/intern/softbody.c46
-rw-r--r--source/blender/blenkernel/intern/sound.c277
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c97
-rw-r--r--source/blender/blenkernel/intern/text.c172
-rw-r--r--source/blender/blenkernel/intern/texture.c122
-rw-r--r--source/blender/blenkernel/intern/tracking.c97
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c16
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c7
-rw-r--r--source/blender/blenkernel/intern/world.c4
-rw-r--r--source/blender/blenkernel/intern/writeavi.c107
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c420
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c132
-rw-r--r--source/blender/blenlib/BLI_array_utils.h8
-rw-r--r--source/blender/blenlib/BLI_astar.h9
-rw-r--r--source/blender/blenlib/BLI_blenlib.h1
-rw-r--r--source/blender/blenlib/BLI_callbacks.h1
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h2
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h299
-rw-r--r--source/blender/blenlib/BLI_edgehash.h1
-rw-r--r--source/blender/blenlib/BLI_fileops.h1
-rw-r--r--source/blender/blenlib/BLI_ghash.h37
-rw-r--r--source/blender/blenlib/BLI_linklist.h56
-rw-r--r--source/blender/blenlib/BLI_linklist_stack.h10
-rw-r--r--source/blender/blenlib/BLI_listbase.h2
-rw-r--r--source/blender/blenlib/BLI_math.h39
-rw-r--r--source/blender/blenlib/BLI_math_base.h6
-rw-r--r--source/blender/blenlib/BLI_math_bits.h51
-rw-r--r--source/blender/blenlib/BLI_math_color.h10
-rw-r--r--source/blender/blenlib/BLI_math_geom.h9
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h1
-rw-r--r--source/blender/blenlib/BLI_math_vector.h28
-rw-r--r--source/blender/blenlib/BLI_path_util.h8
-rw-r--r--source/blender/blenlib/BLI_quadric.h14
-rw-r--r--source/blender/blenlib/BLI_rect.h6
-rw-r--r--source/blender/blenlib/BLI_stack.h2
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h2
-rw-r--r--source/blender/blenlib/BLI_string.h10
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h8
-rw-r--r--source/blender/blenlib/BLI_task.h3
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_utildefines.h18
-rw-r--r--source/blender/blenlib/BLI_winstuff.h13
-rw-r--r--source/blender/blenlib/CMakeLists.txt23
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c8
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c392
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c701
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c2
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c73
-rw-r--r--source/blender/blenlib/intern/array_utils.c41
-rw-r--r--source/blender/blenlib/intern/astar.c14
-rw-r--r--source/blender/blenlib/intern/convexhull2d.c2
-rw-r--r--source/blender/blenlib/intern/edgehash.c66
-rw-r--r--source/blender/blenlib/intern/fileops.c10
-rw-r--r--source/blender/blenlib/intern/freetypefont.c3
-rw-r--r--source/blender/blenlib/intern/gsqueue.c8
-rw-r--r--source/blender/blenlib/intern/hash_md5.c3
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c4
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h341
-rw-r--r--source/blender/blenlib/intern/listbase.c73
-rw-r--r--source/blender/blenlib/intern/math_base.c41
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c19
-rw-r--r--source/blender/blenlib/intern/math_bits_inline.c59
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c68
-rw-r--r--source/blender/blenlib/intern/math_geom.c199
-rw-r--r--source/blender/blenlib/intern/math_interp.c8
-rw-r--r--source/blender/blenlib/intern/math_matrix.c59
-rw-r--r--source/blender/blenlib/intern/math_rotation.c36
-rw-r--r--source/blender/blenlib/intern/math_vector.c78
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c47
-rw-r--r--source/blender/blenlib/intern/path_util.c247
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c7
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c10
-rw-r--r--source/blender/blenlib/intern/quadric.c65
-rw-r--r--source/blender/blenlib/intern/rand.c20
-rw-r--r--source/blender/blenlib/intern/rct.c75
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c12
-rw-r--r--source/blender/blenlib/intern/stack.c78
-rw-r--r--source/blender/blenlib/intern/storage.c323
-rw-r--r--source/blender/blenlib/intern/string.c79
-rw-r--r--source/blender/blenlib/intern/string_utf8.c31
-rw-r--r--source/blender/blenlib/intern/system.c10
-rw-r--r--source/blender/blenlib/intern/task.c24
-rw-r--r--source/blender/blenlib/intern/threads.c68
-rw-r--r--source/blender/blenlib/intern/timecode.c29
-rw-r--r--source/blender/blenlib/intern/winstuff_dir.c40
-rw-r--r--source/blender/blenloader/BLO_readfile.h5
-rw-r--r--source/blender/blenloader/BLO_undofile.h6
-rw-r--r--source/blender/blenloader/SConscript7
-rw-r--r--source/blender/blenloader/intern/readblenentry.c24
-rw-r--r--source/blender/blenloader/intern/readfile.c119
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/undofile.c8
-rw-r--r--source/blender/blenloader/intern/versioning_250.c14
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c213
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c12
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c33
-rw-r--r--source/blender/blenloader/intern/writefile.c146
-rw-r--r--source/blender/bmesh/CMakeLists.txt2
-rw-r--r--source/blender/bmesh/bmesh_class.h30
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c288
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h35
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c756
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h64
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c22
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h22
-rw-r--r--source/blender/bmesh/intern/bmesh_inline.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c42
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c26
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h19
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c81
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c51
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h26
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c56
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c11
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c51
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h58
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c52
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h116
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api_inline.h49
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c124
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c20
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c502
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h66
-rw-r--r--source/blender/bmesh/intern/bmesh_queries_inline.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c115
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_structure_inline.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c360
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_private.h14
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c14
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c27
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c2
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c31
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c70
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c10
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c26
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c47
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c7
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c434
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c290
-rw-r--r--source/blender/bmesh/operators/bmo_planar_faces.c158
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c124
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c128
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c47
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c16
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c24
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c535
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h25
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c241
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c77
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c18
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c112
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c14
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c54
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c7
-rw-r--r--source/blender/collada/AnimationExporter.cpp6
-rw-r--r--source/blender/collada/AnimationExporter.h4
-rw-r--r--source/blender/collada/ArmatureImporter.cpp8
-rw-r--r--source/blender/collada/ControllerExporter.cpp3
-rw-r--r--source/blender/collada/DocumentImporter.cpp4
-rw-r--r--source/blender/collada/DocumentImporter.h1
-rw-r--r--source/blender/collada/GeometryExporter.cpp53
-rw-r--r--source/blender/collada/GeometryExporter.h19
-rw-r--r--source/blender/collada/ImageExporter.cpp2
-rw-r--r--source/blender/collada/SceneExporter.cpp4
-rw-r--r--source/blender/collada/collada.cpp2
-rw-r--r--source/blender/collada/collada_utils.cpp7
-rw-r--r--source/blender/compositor/CMakeLists.txt5
-rw-r--r--source/blender/compositor/COM_compositor.h5
-rw-r--r--source/blender/compositor/SConscript1
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h17
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp8
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp6
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp48
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h5
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp10
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h6
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cpp2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h22
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp7
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.cpp2
-rw-r--r--source/blender/compositor/intern/COM_SocketReader.h18
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp5
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cpp1
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp107
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h2
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cpp51
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h1
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp3
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.cpp42
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.h37
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cpp5
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp17
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cpp33
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp19
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cpp27
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp322
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h75
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp126
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h22
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp14
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h9
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp26
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cpp4
-rw-r--r--source/blender/depsgraph/CMakeLists.txt118
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h215
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h121
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h111
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h195
-rw-r--r--source/blender/depsgraph/SConscript74
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc473
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h224
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc370
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.h408
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_nodes.cc1204
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc1852
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1193
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.h87
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc394
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h168
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc217
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc177
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h91
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc541
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc102
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h173
-rw-r--r--source/blender/depsgraph/intern/depsnode.cc316
-rw-r--r--source/blender/depsgraph/intern/depsnode.h248
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.cc318
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.h201
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h145
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.cc104
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.h90
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.cc140
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.h37
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_function.h112
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h72
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h67
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.cc136
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.h59
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_set.h66
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.cc139
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.h38
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c319
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c264
-rw-r--r--source/blender/editors/animation/anim_deps.c4
-rw-r--r--source/blender/editors/animation/anim_draw.c214
-rw-r--r--source/blender/editors/animation/anim_filter.c128
-rw-r--r--source/blender/editors/animation/anim_markers.c54
-rw-r--r--source/blender/editors/animation/anim_ops.c4
-rw-r--r--source/blender/editors/animation/drivers.c7
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_draw.c2
-rw-r--r--source/blender/editors/animation/keyframes_general.c54
-rw-r--r--source/blender/editors/animation/keyframing.c130
-rw-r--r--source/blender/editors/armature/BIF_retarget.h1
-rw-r--r--source/blender/editors/armature/armature_add.c346
-rw-r--r--source/blender/editors/armature/armature_edit.c317
-rw-r--r--source/blender/editors/armature/armature_intern.h3
-rw-r--r--source/blender/editors/armature/armature_naming.c4
-rw-r--r--source/blender/editors/armature/armature_ops.c10
-rw-r--r--source/blender/editors/armature/armature_relations.c16
-rw-r--r--source/blender/editors/armature/armature_select.c173
-rw-r--r--source/blender/editors/armature/armature_utils.c32
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c4
-rw-r--r--source/blender/editors/armature/meshlaplacian.c8
-rw-r--r--source/blender/editors/armature/meshlaplacian.h2
-rw-r--r--source/blender/editors/armature/pose_edit.c9
-rw-r--r--source/blender/editors/armature/pose_group.c12
-rw-r--r--source/blender/editors/armature/pose_select.c108
-rw-r--r--source/blender/editors/armature/pose_slide.c171
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/curve_intern.h3
-rw-r--r--source/blender/editors/curve/curve_ops.c1
-rw-r--r--source/blender/editors/curve/editcurve.c60
-rw-r--r--source/blender/editors/curve/editcurve_add.c20
-rw-r--r--source/blender/editors/curve/editfont.c55
-rw-r--r--source/blender/editors/curve/lorem.c658
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c102
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c1484
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c447
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1855
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h9
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c142
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c35
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c186
-rw-r--r--source/blender/editors/include/BIF_glutil.h4
-rw-r--r--source/blender/editors/include/ED_anim_api.h25
-rw-r--r--source/blender/editors/include/ED_armature.h20
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h5
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h1
-rw-r--r--source/blender/editors/include/ED_keyframing.h2
-rw-r--r--source/blender/editors/include/ED_lattice.h1
-rw-r--r--source/blender/editors/include/ED_mask.h3
-rw-r--r--source/blender/editors/include/ED_mball.h1
-rw-r--r--source/blender/editors/include/ED_mesh.h49
-rw-r--r--source/blender/editors/include/ED_node.h3
-rw-r--r--source/blender/editors/include/ED_object.h31
-rw-r--r--source/blender/editors/include/ED_outliner.h36
-rw-r--r--source/blender/editors/include/ED_paint.h7
-rw-r--r--source/blender/editors/include/ED_particle.h7
-rw-r--r--source/blender/editors/include/ED_render.h17
-rw-r--r--source/blender/editors/include/ED_screen.h7
-rw-r--r--source/blender/editors/include/ED_sculpt.h1
-rw-r--r--source/blender/editors/include/ED_transform.h7
-rw-r--r--source/blender/editors/include/ED_util.h10
-rw-r--r--source/blender/editors/include/ED_uvedit.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h79
-rw-r--r--source/blender/editors/include/UI_interface.h42
-rw-r--r--source/blender/editors/include/UI_interface_icons.h10
-rw-r--r--source/blender/editors/include/UI_resources.h6
-rw-r--r--source/blender/editors/include/UI_view2d.h1
-rw-r--r--source/blender/editors/interface/interface.c191
-rw-r--r--source/blender/editors/interface/interface_anim.c32
-rw-r--r--source/blender/editors/interface/interface_draw.c11
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c43
-rw-r--r--source/blender/editors/interface/interface_handlers.c859
-rw-r--r--source/blender/editors/interface/interface_icons.c185
-rw-r--r--source/blender/editors/interface/interface_intern.h40
-rw-r--r--source/blender/editors/interface/interface_layout.c67
-rw-r--r--source/blender/editors/interface/interface_ops.c108
-rw-r--r--source/blender/editors/interface/interface_panel.c268
-rw-r--r--source/blender/editors/interface/interface_regions.c114
-rw-r--r--source/blender/editors/interface/interface_style.c8
-rw-r--r--source/blender/editors/interface/interface_templates.c279
-rw-r--r--source/blender/editors/interface/interface_utils.c38
-rw-r--r--source/blender/editors/interface/interface_widgets.c293
-rw-r--r--source/blender/editors/interface/resources.c42
-rw-r--r--source/blender/editors/interface/view2d.c215
-rw-r--r--source/blender/editors/interface/view2d_ops.c101
-rw-r--r--source/blender/editors/mask/mask_add.c14
-rw-r--r--source/blender/editors/mask/mask_draw.c4
-rw-r--r--source/blender/editors/mask/mask_edit.c53
-rw-r--r--source/blender/editors/mask/mask_intern.h1
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add.c39
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c4
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c10
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c31
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c74
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c43
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c258
-rw-r--r--source/blender/editors/mesh/editmesh_select.c1179
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c600
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c195
-rw-r--r--source/blender/editors/mesh/mesh_data.c76
-rw-r--r--source/blender/editors/mesh/mesh_intern.h12
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c7
-rw-r--r--source/blender/editors/mesh/mesh_ops.c17
-rw-r--r--source/blender/editors/mesh/meshtools.c10
-rw-r--r--source/blender/editors/metaball/mball_edit.c5
-rw-r--r--source/blender/editors/object/object_add.c68
-rw-r--r--source/blender/editors/object/object_bake_api.c46
-rw-r--r--source/blender/editors/object/object_constraint.c527
-rw-r--r--source/blender/editors/object/object_data_transfer.c9
-rw-r--r--source/blender/editors/object/object_edit.c88
-rw-r--r--source/blender/editors/object/object_hook.c5
-rw-r--r--source/blender/editors/object/object_intern.h13
-rw-r--r--source/blender/editors/object/object_lattice.c2
-rw-r--r--source/blender/editors/object/object_modifier.c110
-rw-r--r--source/blender/editors/object/object_ops.c8
-rw-r--r--source/blender/editors/object/object_random.c4
-rw-r--r--source/blender/editors/object/object_relations.c29
-rw-r--r--source/blender/editors/object/object_shapekey.c91
-rw-r--r--source/blender/editors/object/object_transform.c6
-rw-r--r--source/blender/editors/object/object_vgroup.c336
-rw-r--r--source/blender/editors/object/object_warp.c4
-rw-r--r--source/blender/editors/physics/particle_edit.c37
-rw-r--r--source/blender/editors/physics/rigidbody_object.c1
-rw-r--r--source/blender/editors/render/render_intern.h8
-rw-r--r--source/blender/editors/render/render_internal.c31
-rw-r--r--source/blender/editors/render/render_opengl.c378
-rw-r--r--source/blender/editors/render/render_ops.c4
-rw-r--r--source/blender/editors/render/render_preview.c191
-rw-r--r--source/blender/editors/render/render_shading.c151
-rw-r--r--source/blender/editors/render/render_update.c36
-rw-r--r--source/blender/editors/render/render_view.c16
-rw-r--r--source/blender/editors/screen/area.c263
-rw-r--r--source/blender/editors/screen/glutil.c41
-rw-r--r--source/blender/editors/screen/screen_context.c24
-rw-r--r--source/blender/editors/screen/screen_edit.c106
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/screen_ops.c58
-rw-r--r--source/blender/editors/screen/screendump.c36
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c24
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c50
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c808
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h8
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c45
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1244
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c16
-rw-r--r--source/blender/editors/sound/sound_intern.h1
-rw-r--r--source/blender/editors/sound/sound_ops.c14
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_action/action_data.c908
-rw-r--r--source/blender/editors/space_action/action_draw.c7
-rw-r--r--source/blender/editors/space_action/action_edit.c458
-rw-r--r--source/blender/editors/space_action/action_intern.h9
-rw-r--r--source/blender/editors/space_action/action_ops.c19
-rw-r--r--source/blender/editors/space_action/action_select.c4
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c31
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h1
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c15
-rw-r--r--source/blender/editors/space_clip/clip_draw.c46
-rw-r--r--source/blender/editors/space_clip/clip_editor.c50
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c22
-rw-r--r--source/blender/editors/space_clip/clip_ops.c4
-rw-r--r--source/blender/editors/space_clip/clip_utils.c46
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c28
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_console/console_intern.h1
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_file/file_draw.c54
-rw-r--r--source/blender/editors/space_file/file_intern.h14
-rw-r--r--source/blender/editors/space_file/file_ops.c327
-rw-r--r--source/blender/editors/space_file/file_utils.c46
-rw-r--r--source/blender/editors/space_file/filelist.c35
-rw-r--r--source/blender/editors/space_file/filelist.h5
-rw-r--r--source/blender/editors/space_file/filesel.c87
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c48
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c23
-rw-r--r--source/blender/editors/space_graph/graph_draw.c34
-rw-r--r--source/blender/editors/space_graph/graph_edit.c90
-rw-r--r--source/blender/editors/space_graph/graph_intern.h4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c18
-rw-r--r--source/blender/editors/space_graph/graph_select.c32
-rw-r--r--source/blender/editors/space_graph/graph_utils.c9
-rw-r--r--source/blender/editors/space_image/image_buttons.c360
-rw-r--r--source/blender/editors/space_image/image_draw.c51
-rw-r--r--source/blender/editors/space_image/image_edit.c8
-rw-r--r--source/blender/editors/space_image/image_intern.h4
-rw-r--r--source/blender/editors/space_image/image_ops.c532
-rw-r--r--source/blender/editors/space_image/space_image.c6
-rw-r--r--source/blender/editors/space_info/info_draw.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c4
-rw-r--r--source/blender/editors/space_info/info_stats.c33
-rw-r--r--source/blender/editors/space_logic/logic_intern.h4
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_channels.c52
-rw-r--r--source/blender/editors/space_nla/nla_draw.c13
-rw-r--r--source/blender/editors/space_nla/nla_edit.c50
-rw-r--r--source/blender/editors/space_nla/nla_intern.h3
-rw-r--r--source/blender/editors/space_nla/nla_ops.c12
-rw-r--r--source/blender/editors/space_node/drawnode.c67
-rw-r--r--source/blender/editors/space_node/node_draw.c15
-rw-r--r--source/blender/editors/space_node/node_edit.c106
-rw-r--r--source/blender/editors/space_node/node_group.c4
-rw-r--r--source/blender/editors/space_node/node_intern.h5
-rw-r--r--source/blender/editors/space_node/node_ops.c2
-rw-r--r--source/blender/editors/space_node/node_select.c6
-rw-r--r--source/blender/editors/space_node/node_templates.c19
-rw-r--r--source/blender/editors/space_node/node_view.c9
-rw-r--r--source/blender/editors/space_node/space_node.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c39
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h7
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c30
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c32
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c190
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c226
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c71
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h10
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c55
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c32
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c9
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c5
-rw-r--r--source/blender/editors/space_text/text_intern.h3
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/editors/space_time/time_intern.h1
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/SConscript1
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c1
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c20
-rw-r--r--source/blender/editors/space_view3d/drawobject.c810
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c7
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c110
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c378
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c340
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h9
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c166
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c67
-rw-r--r--source/blender/editors/transform/CMakeLists.txt4
-rw-r--r--source/blender/editors/transform/SConscript3
-rw-r--r--source/blender/editors/transform/transform.c1460
-rw-r--r--source/blender/editors/transform/transform.h28
-rw-r--r--source/blender/editors/transform/transform_constraints.c58
-rw-r--r--source/blender/editors/transform/transform_conversions.c971
-rw-r--r--source/blender/editors/transform/transform_generics.c78
-rw-r--r--source/blender/editors/transform/transform_manipulator.c17
-rw-r--r--source/blender/editors/transform/transform_ops.c53
-rw-r--r--source/blender/editors/transform/transform_snap.c151
-rw-r--r--source/blender/editors/util/CMakeLists.txt2
-rw-r--r--source/blender/editors/util/ed_util.c26
-rw-r--r--source/blender/editors/util/editmode_undo.c11
-rw-r--r--source/blender/editors/util/numinput.c8
-rw-r--r--source/blender/editors/util/undo.c17
-rw-r--r--source/blender/editors/util/util_intern.h12
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h5
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c155
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/FRS_freestyle.h5
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp2
-rw-r--r--source/blender/freestyle/intern/application/AppView.h4
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp12
-rw-r--r--source/blender/freestyle/intern/application/Controller.h1
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp10
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp10
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h30
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp66
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.h6
-rw-r--r--source/blender/freestyle/intern/image/Image.h2
-rw-r--r--source/blender/freestyle/intern/image/ImagePyramid.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp18
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp8
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp49
-rw-r--r--source/blender/freestyle/intern/python/BPy_IntegrationType.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.cpp40
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp5
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp8
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp8
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h1
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates1D.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp4
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h22
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.cpp8
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.h4
-rw-r--r--source/blender/freestyle/intern/view_map/Interface1D.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h4
-rw-r--r--source/blender/freestyle/intern/view_map/SphericalGrid.cpp8
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.h2
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp12
-rw-r--r--source/blender/gpu/CMakeLists.txt11
-rw-r--r--source/blender/gpu/GPU_buffers.h14
-rw-r--r--source/blender/gpu/GPU_compositing.h13
-rw-r--r--source/blender/gpu/GPU_debug.h2
-rw-r--r--source/blender/gpu/GPU_draw.h14
-rw-r--r--source/blender/gpu/GPU_extensions.h106
-rw-r--r--source/blender/gpu/GPU_material.h120
-rw-r--r--source/blender/gpu/GPU_simple_shader.h8
-rw-r--r--source/blender/gpu/SConscript5
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c248
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c226
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h67
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c821
-rw-r--r--source/blender/gpu/intern/gpu_debug.c42
-rw-r--r--source/blender/gpu/intern/gpu_draw.c569
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c580
-rw-r--r--source/blender/gpu/intern/gpu_material.c505
-rw-r--r--source/blender/gpu/intern/gpu_simple_shader.c3
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_frag.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl166
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl50
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl58
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_lib.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl40
-rw-r--r--source/blender/ikplugin/BIK_api.h1
-rw-r--r--source/blender/ikplugin/CMakeLists.txt4
-rw-r--r--source/blender/ikplugin/intern/ikplugin_api.h1
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp3
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h7
-rw-r--r--source/blender/imbuf/IMB_imbuf.h65
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h4
-rw-r--r--source/blender/imbuf/IMB_thumbs.h18
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h7
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h8
-rw-r--r--source/blender/imbuf/intern/IMB_metadata.h10
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c6
-rw-r--r--source/blender/imbuf/intern/anim_movie.c25
-rw-r--r--source/blender/imbuf/intern/bmp.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c2
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c104
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h24
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h3
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp6
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h12
-rw-r--r--source/blender/imbuf/intern/dds/Stream.h3
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp2
-rw-r--r--source/blender/imbuf/intern/divers.c86
-rw-r--r--source/blender/imbuf/intern/filetype.c12
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/imageprocess.c63
-rw-r--r--source/blender/imbuf/intern/indexer.c31
-rw-r--r--source/blender/imbuf/intern/metadata.c7
-rw-r--r--source/blender/imbuf/intern/moviecache.c4
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp1148
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h45
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp56
-rw-r--r--source/blender/imbuf/intern/png.c19
-rw-r--r--source/blender/imbuf/intern/readimage.c10
-rw-r--r--source/blender/imbuf/intern/rectop.c18
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c1292
-rw-r--r--source/blender/imbuf/intern/targa.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c244
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c4
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c100
-rw-r--r--source/blender/imbuf/intern/tiff.c4
-rw-r--r--source/blender/imbuf/intern/util.c24
-rw-r--r--source/blender/imbuf/intern/writeimage.c40
-rw-r--r--source/blender/makesdna/DNA_ID.h22
-rw-r--r--source/blender/makesdna/DNA_action_types.h4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h4
-rw-r--r--source/blender/makesdna/DNA_brush_types.h45
-rw-r--r--source/blender/makesdna/DNA_camera_types.h27
-rw-r--r--source/blender/makesdna/DNA_color_types.h1
-rw-r--r--source/blender/makesdna/DNA_curve_types.h2
-rw-r--r--source/blender/makesdna/DNA_documentation.h18
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h1
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h2
-rw-r--r--source/blender/makesdna/DNA_image_types.h53
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h3
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h46
-rw-r--r--source/blender/makesdna/DNA_node_types.h9
-rw-r--r--source/blender/makesdna/DNA_object_force.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h18
-rw-r--r--source/blender/makesdna/DNA_packedFile_types.h3
-rw-r--r--source/blender/makesdna/DNA_scene_types.h131
-rw-r--r--source/blender/makesdna/DNA_screen_types.h5
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h2
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h37
-rw-r--r--source/blender/makesdna/DNA_sound_types.h1
-rw-r--r--source/blender/makesdna/DNA_space_types.h28
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h19
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h2
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h23
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h19
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesdna/intern/makesdna.c5
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/RNA_enum_types.h8
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/SConscript1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesrna/intern/SConscript1
-rw-r--r--source/blender/makesrna/intern/makesrna.c18
-rw-r--r--source/blender/makesrna/intern/rna_ID.c248
-rw-r--r--source/blender/makesrna/intern/rna_access.c10
-rw-r--r--source/blender/makesrna/intern/rna_action.c15
-rw-r--r--source/blender/makesrna/intern/rna_animation.c1
-rw-r--r--source/blender/makesrna/intern/rna_armature.c8
-rw-r--r--source/blender/makesrna/intern/rna_brush.c16
-rw-r--r--source/blender/makesrna/intern/rna_camera.c84
-rw-r--r--source/blender/makesrna/intern/rna_color.c14
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c11
-rw-r--r--source/blender/makesrna/intern/rna_controller.c2
-rw-r--r--source/blender/makesrna/intern/rna_curve.c12
-rw-r--r--source/blender/makesrna/intern/rna_define.c8
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c112
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c10
-rw-r--r--source/blender/makesrna/intern/rna_image.c110
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c59
-rw-r--r--source/blender/makesrna/intern/rna_internal.h5
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_key.c3
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c6
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c55
-rw-r--r--source/blender/makesrna/intern/rna_mask.c9
-rw-r--r--source/blender/makesrna/intern/rna_material.c4
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c77
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c49
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c131
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c127
-rw-r--r--source/blender/makesrna/intern/rna_object.c51
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c42
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c2
-rw-r--r--source/blender/makesrna/intern/rna_palette.c181
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_pose.c6
-rw-r--r--source/blender/makesrna/intern/rna_render.c152
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c645
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c16
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c55
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c14
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c116
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c20
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c69
-rw-r--r--source/blender/makesrna/intern/rna_sound.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c271
-rw-r--r--source/blender/makesrna/intern/rna_texture.c6
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c36
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c68
-rw-r--r--source/blender/makesrna/intern/rna_wm.c112
-rw-r--r--source/blender/makesrna/intern/rna_world.c13
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/SConscript1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c13
-rw-r--r--source/blender/modifiers/intern/MOD_array.c35
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c16
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.h2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c43
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c13
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c24
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c1
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c769
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c21
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c24
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c20
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c16
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c22
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c3
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c31
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c20
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c13
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c18
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_util.h2
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c14
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c17
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c1
-rw-r--r--source/blender/modifiers/intern/MOD_none.c1
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c29
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c23
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c15
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c25
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c18
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c13
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c18
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c107
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c9
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c3
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c1
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c20
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c25
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c17
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c16
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c18
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c20
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c23
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_socket.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c7
-rw-r--r--source/blender/nodes/composite/node_composite_util.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.c153
-rw-r--r--source/blender/nodes/intern/node_common.c21
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c3
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c2
-rw-r--r--source/blender/nodes/texture/node_texture_util.h2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c3
-rw-r--r--source/blender/physics/BPH_mass_spring.h4
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp4
-rw-r--r--source/blender/physics/intern/eigen_utils.h2
-rw-r--r--source/blender/physics/intern/hair_volume.cpp2
-rw-r--r--source/blender/physics/intern/implicit.h2
-rw-r--r--source/blender/python/BPY_extern.h1
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c23
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c35
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h9
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c18
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c8
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c16
-rw-r--r--source/blender/python/generic/blf_py_api.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c2
-rw-r--r--source/blender/python/generic/py_capi_utils.c30
-rw-r--r--source/blender/python/generic/py_capi_utils.h1
-rw-r--r--source/blender/python/intern/CMakeLists.txt3
-rw-r--r--source/blender/python/intern/bpy.c2
-rw-r--r--source/blender/python/intern/bpy_app.c30
-rw-r--r--source/blender/python/intern/bpy_app_translations.c12
-rw-r--r--source/blender/python/intern/bpy_app_translations.h1
-rw-r--r--source/blender/python/intern/bpy_interface.c18
-rw-r--r--source/blender/python/intern/bpy_props.c36
-rw-r--r--source/blender/python/intern/bpy_rna.c32
-rw-r--r--source/blender/python/intern/bpy_util.c60
-rw-r--r--source/blender/python/intern/bpy_util.h3
-rw-r--r--source/blender/python/intern/bpy_utils_previews.c188
-rw-r--r--source/blender/python/intern/bpy_utils_previews.h32
-rw-r--r--source/blender/python/intern/bpy_utils_units.c10
-rw-r--r--source/blender/python/intern/gpu.c31
-rw-r--r--source/blender/python/mathutils/mathutils.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c14
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/quicktime/apple/qtkit_export.m87
-rw-r--r--source/blender/quicktime/quicktime_export.h13
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/SConscript1
-rw-r--r--source/blender/render/extern/include/RE_bake.h10
-rw-r--r--source/blender/render/extern/include/RE_engine.h11
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h71
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h2
-rw-r--r--source/blender/render/intern/include/initrender.h1
-rw-r--r--source/blender/render/intern/include/occlusion.h3
-rw-r--r--source/blender/render/intern/include/pixelshading.h1
-rw-r--r--source/blender/render/intern/include/pointdensity.h4
-rw-r--r--source/blender/render/intern/include/render_result.h23
-rw-r--r--source/blender/render/intern/include/render_types.h9
-rw-r--r--source/blender/render/intern/include/rendercore.h3
-rw-r--r--source/blender/render/intern/include/shadbuf.h1
-rw-r--r--source/blender/render/intern/include/shading.h1
-rw-r--r--source/blender/render/intern/include/sss.h1
-rw-r--r--source/blender/render/intern/include/strand.h3
-rw-r--r--source/blender/render/intern/include/texture.h5
-rw-r--r--source/blender/render/intern/include/zbuf.h1
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp2
-rw-r--r--source/blender/render/intern/source/bake.c19
-rw-r--r--source/blender/render/intern/source/bake_api.c56
-rw-r--r--source/blender/render/intern/source/convertblender.c40
-rw-r--r--source/blender/render/intern/source/envmap.c17
-rw-r--r--source/blender/render/intern/source/external_engine.c70
-rw-r--r--source/blender/render/intern/source/initrender.c20
-rw-r--r--source/blender/render/intern/source/multires_bake.c10
-rw-r--r--source/blender/render/intern/source/pipeline.c1312
-rw-r--r--source/blender/render/intern/source/pointdensity.c288
-rw-r--r--source/blender/render/intern/source/rayshade.c39
-rw-r--r--source/blender/render/intern/source/render_result.c816
-rw-r--r--source/blender/render/intern/source/render_texture.c61
-rw-r--r--source/blender/render/intern/source/rendercore.c111
-rw-r--r--source/blender/render/intern/source/shadeinput.c11
-rw-r--r--source/blender/render/intern/source/shadeoutput.c92
-rw-r--r--source/blender/render/intern/source/texture_ocean.c2
-rw-r--r--source/blender/render/intern/source/volumetric.c12
-rw-r--r--source/blender/render/intern/source/zbuf.c62
-rw-r--r--source/blender/windowmanager/CMakeLists.txt8
-rw-r--r--source/blender/windowmanager/SConscript1
-rw-r--r--source/blender/windowmanager/WM_api.h28
-rw-r--r--source/blender/windowmanager/WM_keymap.h3
-rw-r--r--source/blender/windowmanager/WM_types.h30
-rw-r--r--source/blender/windowmanager/intern/wm.c4
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c23
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c284
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c289
-rw-r--r--source/blender/windowmanager/intern/wm_files.c28
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c50
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c19
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c42
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c345
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c349
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c599
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c11
-rw-r--r--source/blender/windowmanager/intern/wm_window.c124
-rw-r--r--source/blender/windowmanager/wm.h8
-rw-r--r--source/blender/windowmanager/wm_draw.h21
-rw-r--r--source/blender/windowmanager/wm_event_system.h12
-rw-r--r--source/blender/windowmanager/wm_window.h11
1231 files changed, 63431 insertions, 22983 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index d87d5dfc2cc..9a73921bbc7 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -102,6 +102,7 @@ add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
+add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(physics)
add_subdirectory(gpu)
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 64eca6a62db..e987b6be779 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -33,6 +33,7 @@ SConscript(['avi/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',
+ 'depsgraph/SConscript',
'gpu/SConscript',
'editors/SConscript',
'imbuf/SConscript',
diff --git a/source/blender/avi/AVI_avi.h b/source/blender/avi/AVI_avi.h
index 44ffaad1f48..5e9fe378c38 100644
--- a/source/blender/avi/AVI_avi.h
+++ b/source/blender/avi/AVI_avi.h
@@ -28,18 +28,17 @@
/** \file AVI_avi.h
* \ingroup avi
- * \section aviabout AVI module external interface
*
- * \subsection about About the AVI module
+ * \section avi_about About the AVI module
*
* This is external code. It provides avi file import/export and
* conversions. It has been adapted to make use of Blender memory
* management functions, and because of this it needs module
* blenlib. You need to provide this lib when linking with libavi.a .
*
- * \subsection issues Known issues with AVI
+ * \subsection avi_issues Known issues with AVI
*
- * - avi uses mallocN, freeN from blenlib.
+ * - avi uses #MEM_mallocN, #MEM_freeN from blenlib.
* - Not all functions that are used externally are properly
* prototyped.
*
diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c
index 857501c5796..1fa9da6b3a2 100644
--- a/source/blender/avi/intern/avi_mjpeg.c
+++ b/source/blender/avi/intern/avi_mjpeg.c
@@ -290,17 +290,6 @@ static void deinterlace(int odd, unsigned char *to, unsigned char *from, int wid
}
}
-static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int bufsize)
-{
- return Decode_JPEG(inbuf, outbuf, width, height, bufsize);
-}
-
-static void check_and_compress_jpeg(int quality, unsigned char *outbuf, const unsigned char *inbuf,
- int width, int height, int bufsize)
-{
- Compress_JPEG(quality, outbuf, inbuf, width, height, bufsize);
-}
-
void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size)
{
int deint;
@@ -310,7 +299,7 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffe
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1");
- deint = check_and_decode_jpeg(buffer, buf, movie->header->Width, movie->header->Height, *size);
+ deint = Decode_JPEG(buffer, buf, movie->header->Width, movie->header->Height, *size);
MEM_freeN(buffer);
@@ -335,11 +324,11 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer,
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1");
if (!movie->interlace) {
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf, buffer,
- movie->header->Width,
- movie->header->Height,
- bufsize);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf, buffer,
+ movie->header->Width,
+ movie->header->Height,
+ bufsize);
}
else {
deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height);
@@ -348,18 +337,18 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer,
buffer = buf;
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2");
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf, buffer,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf, buffer,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
*size += numbytes;
numbytes = 0;
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
}
*size += numbytes;
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 206345582b2..09734bd9754 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -186,6 +186,12 @@ char **BLF_dir_get(int *ndir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* Free the data return by BLF_dir_get. */
void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
+/* blf_thumbs.c */
+void BLF_thumb_preview(
+ const char *filename, const char **draw_str, const unsigned char draw_str_lines,
+ const float font_color[4], const int font_size,
+ unsigned char *buf, int w, int h, int channels) ATTR_NONNULL();
+
#ifdef DEBUG
void BLF_state_print(int fontid);
#endif
diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h
index b42e6f80022..c9b0c253ed4 100644
--- a/source/blender/blenfont/BLF_translation.h
+++ b/source/blender/blenfont/BLF_translation.h
@@ -79,9 +79,11 @@ bool BLF_is_default_context(const char *msgctxt);
const char *BLF_pgettext(const char *msgctxt, const char *msgid);
/* translation */
+bool BLF_translate(void);
bool BLF_translate_iface(void);
bool BLF_translate_tooltips(void);
bool BLF_translate_new_dataname(void);
+const char *BLF_translate_do(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid);
@@ -180,8 +182,7 @@ const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid
#define BLF_I18NCONTEXT_ID_MASK "Mask"
/* Helper for bpy.app.i18n object... */
-typedef struct
-{
+typedef struct {
const char *c_id;
const char *py_id;
const char *value;
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index 392a9ede100..059e2cac680 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -29,7 +29,6 @@ set(INC
../gpu
../makesdna
../makesrna
- ../python
../imbuf
../../../intern/guardedalloc
../../../intern/glew-mx
@@ -47,6 +46,7 @@ set(SRC
intern/blf_font.c
intern/blf_glyph.c
intern/blf_lang.c
+ intern/blf_thumbs.c
intern/blf_translation.c
intern/blf_util.c
@@ -66,7 +66,13 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_PYTHON)
+ add_definitions(-DWITH_PYTHON)
+ list(APPEND INC
+ ../python
+ )
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_blenfont "${SRC}" "${INC}" "${INC_SYS}")
-
diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript
index b6cf052a980..61d2ca9b12d 100644
--- a/source/blender/blenfont/SConscript
+++ b/source/blender/blenfont/SConscript
@@ -44,7 +44,6 @@ incs = [
'../imbuf',
'../makesdna',
'../makesrna',
- '../python',
]
incs.extend(Split(env['BF_FREETYPE_INC']))
@@ -57,6 +56,10 @@ if sys.platform == 'win32' or env['OURPLATFORM'] == 'linuxcross':
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_PYTHON']:
+ defs.append('WITH_PYTHON')
+ incs.append('../python')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 087c7c7345e..2057b0f6bbf 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -286,10 +286,9 @@ void blf_font_buffer(FontBLF *font, const char *str)
(unsigned char)(buf_info->col[2] * 255),
(unsigned char)(buf_info->col[3] * 255)};
- unsigned char *cbuf;
int chx, chy;
int y, x;
- float a, *fbuf;
+ float a;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@@ -349,8 +348,12 @@ void blf_font_buffer(FontBLF *font, const char *str)
a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
if (a > 0.0f) {
+ const size_t buf_ofs = (
+ ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ (size_t)buf_info->ch);
+ float *fbuf = buf_info->fbuf + buf_ofs;
float alphatest;
- fbuf = buf_info->fbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w));
+
if (a >= 1.0f) {
fbuf[0] = b_col_float[0];
fbuf[1] = b_col_float[1];
@@ -375,13 +378,17 @@ void blf_font_buffer(FontBLF *font, const char *str)
if (buf_info->cbuf) {
int yb = yb_start;
- for (y = 0; y < height_clip; y++) {
- for (x = 0; x < width_clip; x++) {
+ for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
+ for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
if (a > 0.0f) {
+ const size_t buf_ofs = (
+ ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ (size_t)buf_info->ch);
+ unsigned char *cbuf = buf_info->cbuf + buf_ofs;
int alphatest;
- cbuf = buf_info->cbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w));
+
if (a >= 1.0f) {
cbuf[0] = b_col_char[0];
cbuf[1] = b_col_char[1];
@@ -667,6 +674,28 @@ float blf_font_fixed_width(FontBLF *font)
return g->advance;
}
+int blf_font_count_missing_chars(FontBLF *font, const char *str, const size_t len, int *r_tot_chars)
+{
+ int missing = 0;
+ size_t i = 0;
+
+ *r_tot_chars = 0;
+ while (i < len) {
+ unsigned int c;
+
+ if ((c = str[i]) < 0x80) {
+ i++;
+ }
+ else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) {
+ if (FT_Get_Char_Index((font)->face, c) == 0) {
+ missing++;
+ }
+ }
+ (*r_tot_chars)++;
+ }
+ return missing;
+}
+
void blf_font_free(FontBLF *font)
{
GlyphCacheBLF *gc;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c65a0825a49..215d2484c18 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -199,7 +199,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
GlyphBLF *g;
FT_Error err;
FT_Bitmap bitmap, tempbitmap;
- int sharp = (U.text_render & USER_TEXT_DISABLE_AA);
+ const bool is_sharp = (U.text_render & USER_TEXT_DISABLE_AA) != 0;
int flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
FT_BBox bbox;
unsigned int key;
@@ -224,7 +224,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
if (font->flags & BLF_HINTING)
flags &= ~FT_LOAD_NO_HINTING;
- if (sharp)
+ if (is_sharp)
err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO);
else
err = FT_Load_Glyph(font->face, (FT_UInt)index, flags);
@@ -237,7 +237,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
/* get the glyph. */
slot = font->face->glyph;
- if (sharp) {
+ if (is_sharp) {
err = FT_Render_Glyph(slot, FT_RENDER_MODE_MONO);
/* Convert result from 1 bit per pixel to 8 bit per pixel */
@@ -266,7 +266,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
g->height = (int)bitmap.rows;
if (g->width && g->height) {
- if (sharp) {
+ if (is_sharp) {
/* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
int i;
for (i = 0; i < (g->width * g->height); i++) {
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 39b3e3397be..85410a4d856 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -62,6 +62,9 @@ void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len
float blf_font_width(struct FontBLF *font, const char *str, size_t len);
float blf_font_height(struct FontBLF *font, const char *str, size_t len);
float blf_font_fixed_width(struct FontBLF *font);
+
+int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const size_t len, int *r_tot_chars);
+
void blf_font_free(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index da756d65483..1404b9de250 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -48,7 +48,7 @@ typedef struct GlyphCacheBLF {
struct GlyphBLF *glyph_ascii_table[256];
/* texture array, to draw the glyphs. */
- GLuint *textures;
+ unsigned int *textures;
/* size of the array. */
unsigned int ntex;
@@ -103,7 +103,7 @@ typedef struct GlyphBLF {
int advance_i;
/* texture id where this glyph is store. */
- GLuint tex;
+ unsigned int tex;
/* position inside the texture where this glyph is store. */
int xoff;
diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c
index 99e1aa5d3e3..4683081a1ed 100644
--- a/source/blender/blenfont/intern/blf_lang.c
+++ b/source/blender/blenfont/intern/blf_lang.c
@@ -284,12 +284,15 @@ void BLF_lang_set(const char *str)
const char *BLF_lang_get(void)
{
#ifdef WITH_INTERNATIONAL
- const char *locale = LOCALE(ULANGUAGE);
- if (locale[0] == '\0') {
- /* Default locale, we have to find which one we are actually using! */
- locale = bl_locale_get();
+ if (BLF_translate()) {
+ const char *locale = LOCALE(ULANGUAGE);
+ if (locale[0] == '\0') {
+ /* Default locale, we have to find which one we are actually using! */
+ locale = bl_locale_get();
+ }
+ return locale;
}
- return locale;
+ return "en_US"; /* Kind of default locale in Blender when no translation enabled. */
#else
return "";
#endif
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
new file mode 100644
index 00000000000..4b7a568b8b0
--- /dev/null
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -0,0 +1,121 @@
+/*
+ * ***** 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): Thomas Beck
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenfont/intern/blf_thumbs.c
+ * \ingroup blf
+ *
+ * Utility function to generate font preview images.
+ *
+ * Isolate since this needs to be called by #ImBuf code (bad level call).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_threads.h"
+
+#include "blf_internal.h"
+#include "blf_internal_types.h"
+
+#include "BLF_api.h"
+#include "BLF_translation.h"
+
+#include "BLI_strict_flags.h"
+
+/**
+ * This function is used for generating thumbnail previews.
+ *
+ * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
+ */
+void BLF_thumb_preview(
+ const char *filename,
+ const char **draw_str, const unsigned char draw_str_lines,
+ const float font_color[4], const int font_size,
+ unsigned char *buf, int w, int h, int channels)
+{
+ const unsigned int dpi = 72;
+ const int font_size_min = 6;
+ int font_size_curr;
+ /* shrink 1/th each line */
+ int font_shrink = 4;
+
+ FontBLF *font;
+ int i;
+
+ /* Create a new blender font obj and fill it with default values */
+ font = blf_font_new("thumb_font", filename);
+ if (!font) {
+ printf("Info: Can't load font '%s', no preview possible\n", filename);
+ return;
+ }
+
+ /* Would be done via the BLF API, but we're not using a fontid here */
+ font->buf_info.cbuf = buf;
+ font->buf_info.ch = channels;
+ font->buf_info.w = w;
+ font->buf_info.h = h;
+
+ /* Always create the image with a white font,
+ * the caller can theme how it likes */
+ memcpy(font->buf_info.col, font_color, sizeof(font->buf_info.col));
+ font->pos[1] = (float)h;
+
+ font_size_curr = font_size;
+
+ for (i = 0; i < draw_str_lines; i++) {
+ const char *draw_str_i18n = BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, draw_str[i]);
+ const size_t draw_str_i18n_len = strlen(draw_str_i18n);
+ int draw_str_i18n_nbr = 0;
+
+ blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+
+ /* decrease font size each time */
+ font_size_curr -= (font_size_curr / font_shrink);
+ font_shrink += 1;
+
+ font->pos[1] -= font->glyph_cache->ascender * 1.1f;
+
+ /* We fallback to default english strings in case not enough chars are available in current font for given
+ * translated string (useful in non-latin i18n context, like chinese, since many fonts will then show
+ * nothing but ugly 'missing char' in their preview).
+ * Does not handle all cases, but much better than nothing.
+ */
+ if (blf_font_count_missing_chars(
+ font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2))
+ {
+ blf_font_buffer(font, draw_str[i]);
+ }
+ else {
+ blf_font_buffer(font, draw_str_i18n);
+ }
+ }
+
+ blf_font_free(font);
+}
diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c
index 2a4a152f0eb..5d828d9b7be 100644
--- a/source/blender/blenfont/intern/blf_translation.c
+++ b/source/blender/blenfont/intern/blf_translation.c
@@ -46,7 +46,9 @@
#include "DNA_userdef_types.h" /* For user settings. */
+#ifdef WITH_PYTHON
#include "BPY_extern.h"
+#endif
#ifdef WITH_INTERNATIONAL
@@ -152,9 +154,11 @@ const char *BLF_pgettext(const char *msgctxt, const char *msgid)
/* We assume if the returned string is the same (memory level) as the msgid, no translation was found,
* and we can try py scripts' ones!
*/
+#ifdef WITH_PYTHON
if (ret == msgid) {
ret = BPY_app_translations_py_pgettext(msgctxt, msgid);
}
+#endif
}
return ret;
@@ -164,6 +168,15 @@ const char *BLF_pgettext(const char *msgctxt, const char *msgid)
#endif
}
+bool BLF_translate(void)
+{
+#ifdef WITH_INTERNATIONAL
+ return (U.transopts & USER_DOTRANSLATE) != 0;
+#else
+ return false;
+#endif
+}
+
bool BLF_translate_iface(void)
{
#ifdef WITH_INTERNATIONAL
@@ -191,6 +204,21 @@ bool BLF_translate_new_dataname(void)
#endif
}
+const char *BLF_translate_do(const char *msgctxt, const char *msgid)
+{
+#ifdef WITH_INTERNATIONAL
+ if (BLF_translate()) {
+ return BLF_pgettext(msgctxt, msgid);
+ }
+ else {
+ return msgid;
+ }
+#else
+ (void)msgctxt;
+ return msgid;
+#endif
+}
+
const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid)
{
#ifdef WITH_INTERNATIONAL
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 236eae29967..789d86b7816 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -97,7 +97,6 @@ struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
struct BMEditMesh;
-struct ListBase;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
@@ -115,11 +114,6 @@ typedef struct DMCoNo {
float no[3];
} DMCoNo;
-typedef struct DMGridAdjacency {
- int index[4];
- int rotation[4];
-} DMGridAdjacency;
-
/* keep in sync with MFace/MPoly types */
typedef struct DMFlagMat {
short mat_nr;
@@ -290,7 +284,6 @@ struct DerivedMesh {
int (*getNumGrids)(DerivedMesh *dm);
int (*getGridSize)(DerivedMesh *dm);
struct CCGElem **(*getGridData)(DerivedMesh * dm);
- DMGridAdjacency *(*getGridAdjacency)(DerivedMesh * dm);
int *(*getGridOffset)(DerivedMesh * dm);
void (*getGridKey)(DerivedMesh *dm, struct CCGKey *key);
DMFlagMat *(*getGridFlagMats)(DerivedMesh * dm);
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 57ba6fd55ca..3fceef5d95d 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -46,8 +46,6 @@ struct bItasc;
struct bPoseChannel;
struct Main;
struct Object;
-struct Scene;
-struct ID;
/* Kernel prototypes */
#ifdef __cplusplus
@@ -142,6 +140,10 @@ void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_us
void BKE_pose_channels_hash_make(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
+void BKE_pose_channels_remove(
+ struct Object *ob,
+ bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data);
+
void BKE_pose_free(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);
@@ -161,6 +163,9 @@ void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* sets constraint flags */
void BKE_pose_update_constraint_flags(struct bPose *pose);
+/* tag constraint flags for update */
+void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
+
/* return the name of structure pointed by pose->ikparam */
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
@@ -197,6 +202,9 @@ bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
+/* Tag pose for recalc. Also tag all related data to be recalc. */
+void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
+
#ifdef __cplusplus
};
#endif
diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h
index 9c09fffe0a0..74c1edd1c1b 100644
--- a/source/blender/blenkernel/BKE_addon.h
+++ b/source/blender/blenkernel/BKE_addon.h
@@ -38,7 +38,7 @@ typedef struct bAddonPrefType {
bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet);
void BKE_addon_pref_type_add(bAddonPrefType *apt);
-void BKE_addon_pref_type_remove(bAddonPrefType *apt);
+void BKE_addon_pref_type_remove(const bAddonPrefType *apt);
void BKE_addon_pref_type_init(void);
void BKE_addon_pref_type_free(void);
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index 0d5078bc026..584f0da323a 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -35,7 +35,6 @@
struct EvaluationContext;
struct Path;
struct Object;
-struct PartEff;
struct Scene;
struct ListBase;
struct bAnimVizSettings;
@@ -81,7 +80,7 @@ typedef struct DupliApplyData {
DupliExtraData *extra;
} DupliApplyData;
-DupliApplyData *duplilist_apply(struct Object *ob, struct ListBase *duplilist);
+DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist);
void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data);
void duplilist_free_apply_data(DupliApplyData *apply_data);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 0acfd40a110..dc751747f32 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -56,22 +56,22 @@ bool id_type_can_have_animdata(struct ID *id);
struct AnimData *BKE_animdata_from_id(struct ID *id);
/* Add AnimData to the given ID-block */
-struct AnimData *BKE_id_add_animdata(struct ID *id);
+struct AnimData *BKE_animdata_add_id(struct ID *id);
/* Set active action used by AnimData from the given ID-block */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
/* Free AnimData */
-void BKE_free_animdata(struct ID *id);
+void BKE_animdata_free(struct ID *id);
/* Copy AnimData */
-struct AnimData *BKE_copy_animdata(struct AnimData *adt, const bool do_action);
+struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
/* Copy AnimData */
-bool BKE_copy_animdata_id(struct ID *id_to, struct ID *id_from, const bool do_action);
+bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */
-void BKE_copy_animdata_id_action(struct ID *id);
+void BKE_animdata_copy_id_action(struct ID *id);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
@@ -91,7 +91,7 @@ void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_Mer
void BKE_animdata_make_local(struct AnimData *adt);
/* Re-Assign ID's */
-void BKE_relink_animdata(struct AnimData *adt);
+void BKE_animdata_relink(struct AnimData *adt);
/* ************************************* */
/* KeyingSets API */
@@ -134,7 +134,7 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st
bool verify_paths);
/* Fix all the paths for the entire database... */
-void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
+void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
/* Fix the path after removing elements that are not ID (e.g., node) */
void BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
@@ -175,6 +175,9 @@ void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct An
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime);
+/* TODO(sergey): This is mainly a temp public function. */
+struct FCurve;
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
@@ -192,4 +195,13 @@ void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act,
/* ************************************* */
+/* ------------ Evaluation API --------------- */
+
+struct EvaluationContext;
+
+void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id);
+void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve);
+
+/* ************************************* */
+
#endif /* __BKE_ANIMSYS_H__*/
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 5e42f17be03..077fe2a629c 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -38,6 +38,11 @@ void BKE_appdir_program_path_init(const char *argv0);
const char *BKE_appdir_program_path(void);
const char *BKE_appdir_program_dir(void);
+/* find python executable */
+bool BKE_appdir_program_python_search(
+ char *fullpath, const size_t fullpath_len,
+ const int version_major, const int version_minor);
+
/* Initialize path to temporary directory. */
void BKE_tempdir_init(char *userdir);
void BKE_tempdir_system_init(char *dir);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 66e204e51e0..a834a83ca00 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -36,13 +36,10 @@
struct Bone;
struct Main;
struct bArmature;
-struct bPose;
struct bPoseChannel;
struct bConstraint;
struct Scene;
struct Object;
-struct MDeformVert;
-struct Mesh;
struct PoseTree;
struct ListBase;
@@ -145,6 +142,57 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
+/* Evaluation helpers */
+struct bKinematicConstraint;
+struct bPose;
+struct bSplineIKConstraint;
+struct EvaluationContext;
+
+struct bPoseChannel *BKE_armature_ik_solver_find_root(
+ struct bPoseChannel *pchan,
+ struct bKinematicConstraint *data);
+struct bPoseChannel *BKE_armature_splineik_solver_find_root(
+ struct bPoseChannel *pchan,
+ struct bSplineIKConstraint *data);
+
+void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime);
+void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+
+void BKE_pose_eval_init(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 Object *ob,
+ struct bPoseChannel *pchan);
+
+void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
+ struct bPoseChannel *pchan);
+
+void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *rootchan);
+
+void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *rootchan);
+
+void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPose *pose);
+
+void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
+ struct Object *ob);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index dad7f1916a1..8367fd4369f 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -41,8 +41,8 @@ extern "C" {
/* 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 274
-#define BLENDER_SUBVERSION 0
+#define BLENDER_VERSION 275
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
@@ -55,7 +55,6 @@ extern "C" {
extern char versionstr[]; /* from blender.c */
-struct ListBase;
struct MemFile;
struct bContext;
struct ReportList;
@@ -88,21 +87,21 @@ void BKE_userdef_free(void);
void BKE_userdef_state(void);
/* set this callback when a UI is running */
-void set_blender_test_break_cb(void (*func)(void));
+void BKE_blender_callback_test_break_set(void (*func)(void));
int blender_test_break(void);
#define BKE_UNDO_STR_MAX 64
/* global undo */
-extern void BKE_write_undo(struct bContext *C, const char *name);
-extern void BKE_undo_step(struct bContext *C, int step);
-extern void BKE_undo_name(struct bContext *C, const char *name);
-extern int BKE_undo_valid(const char *name);
-extern void BKE_reset_undo(void);
-extern void BKE_undo_number(struct bContext *C, int nr);
-extern const char *BKE_undo_get_name(int nr, int *active);
-extern bool BKE_undo_save_file(const char *filename);
-extern struct Main *BKE_undo_get_main(struct Scene **scene);
+extern void BKE_undo_write(struct bContext *C, const char *name);
+extern void BKE_undo_step(struct bContext *C, int step);
+extern void BKE_undo_name(struct bContext *C, const char *name);
+extern bool BKE_undo_is_valid(const char *name);
+extern void BKE_undo_reset(void);
+extern void BKE_undo_number(struct bContext *C, int nr);
+extern const char *BKE_undo_get_name(int nr, bool *r_active);
+extern bool BKE_undo_save_file(const char *filename);
+extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
/* copybuffer */
void BKE_copybuffer_begin(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index 990b414a4cf..10ee504f244 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -48,13 +48,21 @@ void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
void BKE_bpath_list_free(void *ls_handle);
-#define BKE_BPATH_TRAVERSE_ABS (1 << 0) /* convert paths to absolute */
-#define BKE_BPATH_TRAVERSE_SKIP_LIBRARY (1 << 2) /* skip library paths */
-#define BKE_BPATH_TRAVERSE_SKIP_PACKED (1 << 3) /* skip packed data */
-#define BKE_BPATH_TRAVERSE_SKIP_MULTIFILE (1 << 4) /* skip paths where a single dir is used with an array of files, eg.
- * sequence strip images and pointcache. in this case only use the first
- * file, this is needed for directory manipulation functions which might
- * otherwise modify the same directory multiple times */
+enum {
+ /* convert paths to absolute */
+ BKE_BPATH_TRAVERSE_ABS = (1 << 0),
+ /* skip library paths */
+ BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
+ /* skip packed data */
+ BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
+ /* skip paths where a single dir is used with an array of files, eg.
+ * sequence strip images and pointcache. in this case only use the first
+ * file, this is needed for directory manipulation functions which might
+ * otherwise modify the same directory multiple times */
+ BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
+ /* reload data (when the path is edited) */
+ BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
+};
/* high level funcs */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 49975fa0276..042fba7294c 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -27,14 +27,11 @@
* General operations for brushes.
*/
-struct ID;
struct Brush;
struct ImBuf;
struct ImagePool;
struct Main;
-struct rctf;
struct Scene;
-struct wmOperator;
// enum CurveMappingPreset;
@@ -66,6 +63,7 @@ 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);
/* sampling */
@@ -82,34 +80,36 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondar
/* unified strength size and color */
-float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush);
-float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush);
+const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush);
+const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]);
-int BKE_brush_size_get(const struct Scene *scene, struct Brush *brush);
+int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value);
-float BKE_brush_unprojected_radius_get(const struct Scene *scene, struct Brush *brush);
+float BKE_brush_unprojected_radius_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value);
-float BKE_brush_alpha_get(const struct Scene *scene, struct Brush *brush);
+float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha);
-float BKE_brush_weight_get(const Scene *scene, struct Brush *brush);
+float BKE_brush_weight_get(const Scene *scene, const struct Brush *brush);
void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value);
-int BKE_brush_use_locked_size(const struct Scene *scene, struct Brush *brush);
-int BKE_brush_use_alpha_pressure(const struct Scene *scene, struct Brush *brush);
-int BKE_brush_use_size_pressure(const struct Scene *scene, struct Brush *brush);
+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);
/* scale unprojected radius to reflect a change in the brush's 2D size */
-void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
- int new_brush_size,
- int old_brush_size);
+void BKE_brush_scale_unprojected_radius(
+ float *unprojected_radius,
+ int new_brush_size,
+ int old_brush_size);
/* scale brush size to reflect a change in the brush's unprojected radius */
-void BKE_brush_scale_size(int *BKE_brush_size_get,
- float new_unprojected_radius,
- float old_unprojected_radius);
+void BKE_brush_scale_size(
+ int *r_brush_size,
+ float new_unprojected_radius,
+ float old_unprojected_radius);
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 77296920ee2..aacb7a4066b 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -104,26 +104,45 @@ typedef struct CameraParams {
float winmat[4][4];
} CameraParams;
+/* values for CameraParams.zoom, need to be taken into account for some operations */
+#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f
+#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f
+
void BKE_camera_params_init(CameraParams *params);
-void BKE_camera_params_from_object(CameraParams *params, struct Object *camera);
-void BKE_camera_params_from_view3d(CameraParams *params, struct View3D *v3d, struct RegionView3D *rv3d);
+void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera);
+void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d);
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy);
void BKE_camera_params_compute_matrix(CameraParams *params);
/* Camera View Frame */
-void BKE_camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float drawsize, const bool do_clip, const float scale[3],
- float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]);
+void BKE_camera_view_frame_ex(
+ const struct Scene *scene, const struct Camera *camera,
+ const float drawsize, const bool do_clip, const float scale[3],
+ float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]);
+void BKE_camera_view_frame(
+ const struct Scene *scene, const struct Camera *camera,
+ float r_vec[4][3]);
+
+bool BKE_camera_view_frame_fit_to_scene(
+ struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
+ float r_co[3], float *r_scale);
+bool BKE_camera_view_frame_fit_to_coords(
+ const struct Scene *scene,
+ const float (*cos)[3], int num_cos,
+ const struct Object *camera_ob,
+ float r_co[3], float *r_scale);
-void BKE_camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]);
+void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
-bool BKE_camera_view_frame_fit_to_scene(struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
- float r_co[3], float *r_scale);
-bool BKE_camera_view_frame_fit_to_coords(struct Scene *scene, float (*cos)[3], int num_cos,
- struct Object *camera_ob, float r_co[3], float *r_scale);
+/* Camera multi-view API */
-void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
+struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
+void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
+float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index a7fad85ed42..81621f9d3e7 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -36,15 +36,11 @@
#include "BLI_math_inline.h"
struct Object;
-struct ListBase;
struct Scene;
struct MFace;
struct DerivedMesh;
struct ClothModifierData;
struct CollisionModifierData;
-struct CollisionTree;
-struct VoxelData;
-struct PartDeflect;
#define DO_INLINE MALWAYS_INLINE
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index b81b8f04817..bdc20324bee 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -43,16 +43,12 @@
#include "BLI_kdopbvh.h"
-struct Cloth;
-struct ClothModifierData;
struct CollisionModifierData;
-struct DerivedMesh;
struct Group;
struct MFace;
struct MVert;
struct Object;
struct Scene;
-struct LinkNode;
////////////////////////////////////////
// used for collisions in collision.c
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 9234625a37c..74a327c3808 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -103,5 +103,6 @@ void BKE_color_managed_view_settings_free(struct ColorManagedViewSettings *setti
void BKE_color_managed_colorspace_settings_init(struct ColorManagedColorspaceSettings *colorspace_settings);
void BKE_color_managed_colorspace_settings_copy(struct ColorManagedColorspaceSettings *colorspace_settings,
const struct ColorManagedColorspaceSettings *settings);
-
+bool BKE_color_managed_colorspace_settings_equals(const struct ColorManagedColorspaceSettings *settings1,
+ const struct ColorManagedColorspaceSettings *settings2);
#endif
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 1346feec82c..f3cfb901154 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -108,8 +108,8 @@ typedef struct bConstraintTypeInfo {
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
-bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
-bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
+const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
+const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* ---------------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index ae0ef9ce314..f7af3a7f8ec 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -53,7 +53,6 @@ struct StructRNA;
struct ToolSettings;
struct Image;
struct Text;
-struct ImBuf;
struct EditBone;
struct bPoseChannel;
struct bGPdata;
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 60cbf8b302e..9bae2ad948d 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -33,7 +33,6 @@
* \author nzc
*/
-struct BevList;
struct BezTriple;
struct Curve;
struct EditNurb;
@@ -91,6 +90,7 @@ 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);
int BKE_curve_material_index_validate(struct Curve *cu);
+void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
@@ -120,6 +120,7 @@ void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBa
const bool for_render, const bool use_render_resolution);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
+void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect);
@@ -183,4 +184,14 @@ void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag);
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, const bool use_handle);
void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
+/* **** Depsgraph evaluation **** */
+
+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_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 6a0cfefb1c2..ab49270ca64 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -46,7 +46,6 @@ extern "C" {
struct BMesh;
struct ID;
struct CustomData;
-struct CustomDataLayer;
typedef uint64_t CustomDataMask;
/*a data type large enough to hold 1 element from any customdata layer type*/
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 08312035e40..a45893b00fa 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -39,7 +39,6 @@ struct Object;
struct ListBase;
struct bDeformGroup;
struct MDeformVert;
-struct MVert;
struct MEdge;
struct MLoop;
struct MPoly;
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 27cf19d7d06..862f91f567e 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -48,7 +48,6 @@ struct ID;
struct Main;
struct Object;
struct Scene;
-struct ListBase;
/* Dependency graph evaluation context
*
@@ -57,6 +56,7 @@ struct ListBase;
*/
typedef struct EvaluationContext {
int mode; /* evaluation mode */
+ float ctime; /* evaluation time */
} EvaluationContext;
typedef enum eEvaluationMode {
@@ -92,6 +92,7 @@ void DAG_exit(void);
*/
void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
+void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
void DAG_relations_tag_update(struct Main *bmain);
void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
void DAG_scene_free(struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 0afc457f2b5..3b096773d96 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -53,14 +53,9 @@
/* prototypes */
-struct Base;
struct Scene;
struct Object;
-struct Curve;
struct ListBase;
-struct Material;
-struct Bone;
-struct Mesh;
struct DerivedMesh;
struct EvaluationContext;
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index a8e152fd301..e7384fb1a9c 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -27,8 +27,6 @@
* \ingroup bke
*/
-struct bContext;
-struct wmOperator;
struct Scene;
/* Actual surface point */
@@ -70,8 +68,8 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
struct DynamicPaintSurface *dynamicPaint_createNewSurface(struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
-void dynamicPaint_clearSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
-bool dynamicPaint_resetSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
+bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
void dynamicPaint_freeSurface(struct DynamicPaintSurface *surface);
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 38c8cf12969..d350eea7ac7 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -32,7 +32,6 @@
struct BMesh;
struct BMLoop;
-struct BMFace;
struct Mesh;
struct Scene;
struct DerivedMesh;
@@ -93,11 +92,12 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
void BKE_editmesh_color_free(BMEditMesh *em);
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm,
- struct MeshStatVis *statvis);
+ const struct MeshStatVis *statvis);
float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 3ee7dcd94b8..3736efff146 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -39,7 +39,6 @@ struct BMVert;
struct BMLoop;
struct BMBVHTree;
struct BVHTree;
-struct Scene;
typedef struct BMBVHTree BMBVHTree;
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index c4c27e1060d..f8fee444d91 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -39,11 +39,8 @@
struct Object;
struct Scene;
-struct Effect;
struct ListBase;
-struct Particle;
struct Group;
-struct RNG;
struct ParticleSimulationData;
struct ParticleData;
struct ParticleKey;
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 83783946d4f..443a03a475a 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -172,8 +172,8 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
-FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
-FModifierTypeInfo *get_fmodifier_typeinfo(int type);
+const FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
@@ -223,12 +223,12 @@ struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, c
*/
int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
-/* find an f-curve based on an rna property. */
+/* Find an f-curve based on an rna property. */
struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
- struct AnimData **adt, struct bAction **action, bool *r_driven);
+ struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
/* Same as above, but takes a context data, temp hack needed for complex paths like texture ones. */
struct FCurve *rna_get_fcurve_context_ui(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
- int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven);
+ int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
index 433c10b82f1..6501c968abc 100644
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ b/source/blender/blenkernel/BKE_fluidsim.h
@@ -34,9 +34,7 @@
struct Object;
struct Scene;
-struct FluidsimModifierData;
struct FluidsimSettings;
-struct DerivedMesh;
struct MVert;
/* old interface */
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index e12ce3df476..137670215cc 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -40,8 +40,6 @@ extern "C" {
struct VFont;
struct Object;
struct Curve;
-struct objfnt;
-struct TmpFont;
struct CharInfo;
struct Main;
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index bb909e4aa9d..e10594634f0 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -41,6 +41,7 @@ extern "C" {
struct FreestyleConfig;
struct FreestyleLineSet;
struct FreestyleModuleConfig;
+struct Main;
/* RNA aliases */
typedef struct FreestyleSettings FreestyleSettings;
@@ -58,7 +59,7 @@ bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig
bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
/* FreestyleConfig.linesets */
-FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name);
+FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name);
bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lineset);
FreestyleLineSet *BKE_freestyle_lineset_get_active(FreestyleConfig *config);
short BKE_freestyle_lineset_get_active_index(FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 57003ffc3aa..7585dc23342 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -45,7 +45,6 @@ extern "C" {
/* forwards */
struct Main;
-struct Object;
typedef struct Global {
@@ -127,10 +126,12 @@ enum {
G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */
G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */
G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */
+ G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
+ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* sinle threaded depsgraph */
};
#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_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM)
/* G.fileflags */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 820e1ea1494..d856e90a340 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -36,10 +36,8 @@
struct Base;
struct EvaluationContext;
struct Group;
-struct GroupObject;
struct Main;
struct Object;
-struct bAction;
struct Scene;
void BKE_group_free(struct Group *group);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 9af0d96884a..763a3874d4e 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -48,10 +48,14 @@ typedef struct Icon Icon;
struct PreviewImage;
struct ID;
+enum eIconSizes;
+
void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
-int BKE_icon_getid(struct ID *id);
+int BKE_icon_id_ensure(struct ID *id);
+
+int BKE_icon_preview_ensure(struct PreviewImage *preview);
/* retrieve icon for id */
struct Icon *BKE_icon_get(int icon_id);
@@ -60,8 +64,10 @@ struct Icon *BKE_icon_get(int icon_id);
/* used for inserting the internal icons */
void BKE_icon_set(int icon_id, struct Icon *icon);
-/* remove icon and free date if library object becomes invalid */
-void BKE_icon_delete(struct ID *id);
+/* remove icon and free data if library object becomes invalid */
+void BKE_icon_id_delete(struct ID *id);
+
+void BKE_icon_delete(int icon_id);
/* report changes - icon needs to be recalculated */
void BKE_icon_changed(int icon_id);
@@ -75,8 +81,17 @@ void BKE_previewimg_freefunc(void *link);
/* free the preview image */
void BKE_previewimg_free(struct PreviewImage **prv);
+/* clear the preview image or icon, but does not free it */
+void BKE_previewimg_clear(struct PreviewImage *prv);
+
+/* clear the preview image or icon at a specific size */
+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);
+
/* free the preview image belonging to the id */
-void BKE_previewimg_free_id(struct ID *id);
+void BKE_previewimg_id_free(struct ID *id);
/* create a new preview image */
struct PreviewImage *BKE_previewimg_create(void);
@@ -85,6 +100,19 @@ struct PreviewImage *BKE_previewimg_create(void);
struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
/* retrieve existing or create new preview image */
-struct PreviewImage *BKE_previewimg_get(struct ID *id);
+struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
+
+void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+
+struct PreviewImage *BKE_previewimg_cached_get(const char *name);
+
+struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
+
+struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
+ const char *name, const char *path, const int source, bool force_update);
+
+void BKE_previewimg_cached_release(const char *name);
+
+#define ICON_RENDER_DEFAULT_HEIGHT 32
#endif /* __BKE_ICONS_H__ */
diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h
index 10a34838662..420df77ff1e 100644
--- a/source/blender/blenkernel/BKE_idcode.h
+++ b/source/blender/blenkernel/BKE_idcode.h
@@ -34,6 +34,7 @@
const char *BKE_idcode_to_name(int code);
const char *BKE_idcode_to_name_plural(int code);
+const char *BKE_idcode_to_translation_context(int code);
int BKE_idcode_from_name(const char *name);
bool BKE_idcode_is_linkable(int code);
bool BKE_idcode_is_valid(int code);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 2c9ecef4c2d..facf3cf2103 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -39,41 +39,46 @@ extern "C" {
struct Image;
struct ImBuf;
-struct Tex;
struct anim;
struct Scene;
struct Object;
struct ImageFormatData;
struct ImagePool;
struct Main;
+struct ReportList;
+struct RenderResult;
+struct StampData;
#define IMA_MAX_SPACE 64
void BKE_images_init(void);
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);
/* call from library */
void BKE_image_free(struct Image *image);
-void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf);
-void BKE_image_stamp_buf(
- struct Scene *scene, struct Object *camera,
- unsigned char *rect, float *rectf, int width, int height, int channels);
+typedef void (StampCallback)(void *data, const char *propname, const char *propvalue);
+
+void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr);
+void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
+void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback);
+void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
-int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+int BKE_imbuf_write_stamp(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
-
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
+ const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix);
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames);
-
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
+ const char imtype, const bool use_ext, const bool use_frames, const char *suffix);
+int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
char BKE_image_ftype_to_imtype(const int ftype);
int BKE_image_imtype_to_ftype(const char imtype);
@@ -104,6 +109,7 @@ void BKE_image_tag_time(struct Image *ima);
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
struct ImageUser;
+struct RenderData;
struct RenderPass;
struct RenderResult;
@@ -153,7 +159,7 @@ bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser);
/* same as above, but can be used to retrieve images being rendered in
* a thread safe way, always call both acquire and release */
-struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r);
+struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock);
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
struct ImagePool *BKE_image_pool_new(void);
@@ -173,11 +179,12 @@ struct Image *BKE_image_load_exists(const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
- struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]);
+ struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
/* adds image from imbuf, owns imbuf */
-struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf);
+struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf, const char *name);
/* for reload, refresh, pack */
+void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);
void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
@@ -185,6 +192,8 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
/* ensures an Image exists for viewing nodes or render */
struct Image *BKE_image_verify_viewer(int type, const char *name);
+/* ensures the view node cache is compatible with the scene views */
+void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
@@ -196,13 +205,23 @@ void BKE_image_update_frame(const struct Main *bmain, int cfra);
/* sets index offset for multilayer files */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
+/* sets index offset for multiview files */
+void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
+
/* for multilayer images as well as for render-viewer */
+bool BKE_image_is_multilayer(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
+/* for multilayer images as well as for singlelayer */
+bool BKE_image_is_openexr(struct Image *ima);
+
/* for multiple slot render, call this before render */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima);
-
+
+/* for singlelayer openexr saving */
+bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags);
+
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);
@@ -213,6 +232,8 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
void BKE_image_all_free_anim_ibufs(int except_frame);
void BKE_image_memorypack(struct Image *ima);
+void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
+void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima, char *data, const size_t data_len);
/* prints memory statistics for images */
void BKE_image_print_memlist(void);
@@ -244,7 +265,8 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
-
+bool BKE_image_has_anim(struct Image *image);
+bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_is_animated(struct Image *image);
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_file_format_set(struct Image *image, int ftype);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 9535b921736..abe12282a1b 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -38,7 +38,6 @@ struct ID;
struct ListBase;
struct Curve;
struct Object;
-struct Scene;
struct Lattice;
struct Mesh;
struct WeightsArrayCache;
@@ -66,6 +65,7 @@ float *BKE_key_evaluate_object_ex(
float *BKE_key_evaluate_object(
struct Object *ob, int *r_totelem);
+struct Key **BKE_key_from_object_p(struct Object *ob);
struct Key *BKE_key_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 5fb1053b53f..4ffdb632513 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -93,4 +93,11 @@ int BKE_lattice_index_flip(struct Lattice *lt, const int index,
void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, const short flag,
const bool clear, const bool respecthide);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct Lattice *latt);
+
#endif /* __BKE_LATTICE_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index e88a4e88209..6ecc955e26c 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -107,8 +107,9 @@ void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagg
struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *));
-void set_free_notifier_reference_cb(void (*func)(const void *));
+void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
+void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
+void BKE_library_callback_free_editor_id_reference_set(void (*func)(const struct ID *));
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index ae10ba4caab..e77b4f5e8fe 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -49,9 +49,9 @@ struct Object;
struct ColorBand;
struct bContext;
-FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main);
+FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
-FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle);
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 3db4d9e7324..2f85db4d5d2 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -79,6 +79,7 @@ struct MaskSpline *BKE_mask_spline_copy(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);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 2f20505bea3..0cfa1aeecb5 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -40,8 +40,6 @@ struct Main;
struct Material;
struct ID;
struct Object;
-struct Mesh;
-struct MTFace;
struct Scene;
/* materials */
@@ -52,6 +50,7 @@ void BKE_material_free_ex(struct Material *ma, bool do_id_user);
void test_object_materials(struct Main *bmain, struct ID *id);
void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
void init_material(struct Material *ma);
+void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_material_copy(struct Material *ma);
struct Material *localize_material(struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index c021960e730..62cd50099fd 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -32,7 +32,6 @@
* \since March 2001
* \author nzc
*/
-struct EvaluationContext;
struct Main;
struct MetaBall;
struct Object;
@@ -46,9 +45,6 @@ struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
void BKE_mball_make_local(struct MetaBall *mb);
-void BKE_mball_cubeTable_free(void);
-
-void BKE_mball_polygonize(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
@@ -72,4 +68,11 @@ void BKE_mball_select_all(struct MetaBall *mb);
void BKE_mball_deselect_all(struct MetaBall *mb);
void BKE_mball_select_swap(struct MetaBall *mb);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct MetaBall *mball);
+
#endif
diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h
new file mode 100644
index 00000000000..361f31b704c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mball_tessellate.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MBALL_TESSELLATE_H__
+#define __BKE_MBALL_TESSELLATE_H__
+
+/** \file BKE_mball_tessellate.h
+ * \ingroup bke
+ */
+struct EvaluationContext;
+struct Object;
+struct Scene;
+
+void BKE_mball_polygonize(
+ struct EvaluationContext *eval_ctx, struct Scene *scene,
+ struct Object *ob, struct ListBase *dispbase);
+
+void BKE_mball_cubeTable_free(void);
+
+#endif /* __BKE_MBALL_TESSELLATE_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 224be0f3685..287152baf0a 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -33,13 +33,11 @@
struct ID;
struct BoundBox;
-struct DispList;
struct EdgeHash;
struct ListBase;
struct LinkNode;
struct BLI_Stack;
struct MemArena;
-struct BMEditMesh;
struct BMesh;
struct Main;
struct Mesh;
@@ -49,18 +47,11 @@ struct MFace;
struct MEdge;
struct MVert;
struct MDeformVert;
-struct MCol;
struct Object;
-struct MTFace;
-struct VecNor;
struct CustomData;
struct DerivedMesh;
struct Scene;
struct MLoopUV;
-struct UvVertMap;
-struct UvMapVert;
-struct UvElementMap;
-struct UvElement;
struct ReportList;
#ifdef __cplusplus
@@ -78,12 +69,13 @@ extern "C" {
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
-int poly_find_loop_from_vert(const struct MPoly *poly,
- const struct MLoop *loopstart,
- unsigned vert);
-
-int poly_get_adj_loops_from_vert(unsigned r_adj[3], const struct MPoly *poly,
- const struct MLoop *mloop, unsigned vert);
+int poly_find_loop_from_vert(
+ const struct MPoly *poly,
+ const struct MLoop *loopstart,
+ unsigned vert);
+int poly_get_adj_loops_from_vert(
+ unsigned r_adj[2], const struct MPoly *poly,
+ const struct MLoop *mloop, unsigned vert);
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
@@ -116,6 +108,7 @@ void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblis
void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob);
void BKE_mesh_material_index_remove(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
+void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
@@ -128,7 +121,10 @@ bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, con
const char *new_name, const bool do_tessface);
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
-float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
+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);
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);
@@ -280,7 +276,7 @@ int BKE_mesh_recalc_tessellation(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
struct MVert *mvert,
int totface, int totloop, int totpoly,
- const bool do_face_normals);
+ const bool do_face_nor_copy);
int BKE_mesh_mpoly_to_mface(
struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int totloop, int totpoly);
@@ -364,6 +360,13 @@ void BKE_mesh_strip_loose_edges(struct Mesh *me);
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct Mesh *mesh);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index da44c989146..a2f47858f90 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -102,7 +102,8 @@ typedef struct MeshElemMap {
/* mapping */
UvVertMap *BKE_mesh_uv_vert_map_create(
struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert, int selected, float *limit);
+ unsigned int totpoly, unsigned int totvert,
+ const float limit[2], const bool selected, const bool use_winding);
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 752270a8120..c6d8da16565 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -28,7 +28,6 @@
struct CustomData;
struct DerivedMesh;
struct MVert;
-struct MeshElemMap;
struct MemArena;
/* Generic ways to map some geometry elements from a source mesh to a dest one. */
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 1ec4e23abca..cc53f9409fd 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -39,11 +39,11 @@ struct DagNode;
struct Object;
struct Scene;
struct ListBase;
-struct LinkNode;
struct bArmature;
struct Main;
struct ModifierData;
struct BMEditMesh;
+struct DepsNodeHandle;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -261,6 +261,17 @@ typedef struct ModifierTypeInfo {
struct Main *bmain, struct Scene *scene,
struct Object *ob, struct DagNode *obNode);
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
+ void (*updateDepsgraph)(struct ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ struct DepsNodeHandle *node);
+
/* Should return true if the modifier needs to be recalculated on time
* changes.
*
@@ -313,7 +324,7 @@ typedef struct ModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_modifier_init(void);
-ModifierTypeInfo *modifierType_getInfo(ModifierType type);
+const ModifierTypeInfo *modifierType_getInfo(ModifierType type);
/* Modifier utility calls, do call through type pointer and return
* default values if pointer is optional.
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index a4aa58e22f1..7d7675270de 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -37,7 +37,6 @@ struct Main;
struct MovieClip;
struct MovieClipScopes;
struct MovieClipUser;
-struct MovieTrackingTrack;
struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
@@ -61,7 +60,7 @@ void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr);
void BKE_movieclip_update_scopes(struct MovieClip *clip, struct MovieClipUser *user, struct MovieClipScopes *scopes);
-void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *totseg_r, int **points_r);
+void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *r_totseg, int **r_points);
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
int cfra, int *build_sizes, int build_count, bool undistorted);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 11d81a149b1..a8242a529f3 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -34,9 +34,7 @@
enum MultiresModifiedFlags;
struct DerivedMesh;
-struct GridHidden;
struct MDisps;
-struct MFace;
struct Mesh;
struct ModifierData;
struct Multires;
@@ -81,8 +79,9 @@ struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifier
struct Object *ob);
void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
-void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob,
- int updateblock, int simple);
+void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple);
+void multiresModifier_sync_levels_ex(
+ struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *dst, struct Object *src);
int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd,
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index c3fc29e811f..3bf8bba47f5 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -76,6 +76,8 @@ void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt);
+
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 44ac3b7bb38..4deaf26e2f5 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -62,24 +62,20 @@ struct bNodeTreeExec;
struct bNodeExecContext;
struct bNodeExecData;
struct GPUMaterial;
-struct GPUNode;
struct GPUNodeStack;
struct ID;
struct ImBuf;
struct ImageFormatData;
struct ListBase;
struct Main;
-struct uiBlock;
struct uiLayout;
struct MTex;
struct PointerRNA;
-struct rctf;
struct RenderData;
struct Scene;
struct Tex;
struct SpaceNode;
struct ARegion;
-struct Object;
struct ColorManagedViewSettings;
struct ColorManagedDisplaySettings;
struct bNodeInstanceHash;
@@ -323,7 +319,7 @@ typedef struct bNodeTreeType {
struct bNodeTreeType *ntreeTypeFind(const char *idname);
void ntreeTypeAdd(struct bNodeTreeType *nt);
-void ntreeTypeFreeLink(struct bNodeTreeType *nt);
+void ntreeTypeFreeLink(const struct bNodeTreeType *nt);
bool ntreeIsRegistered(struct bNodeTree *ntree);
struct GHashIterator *ntreeTypeGetIterator(void);
@@ -511,8 +507,7 @@ const struct ListBase *BKE_node_clipboard_get_links(void);
int BKE_node_clipboard_get_type(void);
/* Node Instance Hash */
-typedef struct bNodeInstanceHash
-{
+typedef struct bNodeInstanceHash {
GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */
} bNodeInstanceHash;
@@ -945,6 +940,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_MAP_RANGE 319
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
+#define CMP_NODE_SWITCH_VIEW 322
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -978,9 +974,9 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
/* API */
-struct CompBuf;
void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews,
- const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings);
+ const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 1c6f7221bec..9482ec778d3 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -33,33 +33,31 @@
extern "C" {
#endif
+#include "BLI_compiler_attrs.h"
+
struct Base;
struct EvaluationContext;
struct Scene;
struct Object;
-struct Camera;
struct BoundBox;
struct View3D;
struct SoftBody;
struct BulletSoftBody;
-struct Group;
-struct bAction;
-struct RenderData;
-struct rctf;
struct MovieClip;
struct Main;
struct RigidBodyWorld;
struct HookModifierData;
+struct ModifierData;
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(struct SoftBody *sb, bool copy_caches);
+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 *obn, struct Object *ob);
-void BKE_object_copy_softbody(struct Object *obn, struct Object *ob);
+void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
+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);
void BKE_object_free_bulletsoftbody(struct Object *ob);
@@ -75,7 +73,7 @@ void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *
bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type);
-void BKE_object_link_modifiers(struct Object *ob, struct Object *from);
+void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
@@ -87,9 +85,18 @@ bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
-struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name);
-struct Object *BKE_object_add(struct Main *bmain, struct Scene *scene, int type);
-void *BKE_object_obdata_add_from_type(struct Main *bmain, int type);
+struct Object *BKE_object_add_only_object(
+ struct Main *bmain,
+ int type, const char *name)
+ ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add(
+ struct Main *bmain, struct Scene *scene,
+ int type, const char *name)
+ ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+void *BKE_object_obdata_add_from_type(
+ struct Main *bmain,
+ int type, const char *name)
+ ATTR_NONNULL(1);
void BKE_object_lod_add(struct Object *ob);
void BKE_object_lod_sort(struct Object *ob);
@@ -118,6 +125,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]);
bool BKE_object_pose_context_check(struct Object *ob);
struct Object *BKE_object_pose_armature_get(struct Object *ob);
+void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]);
void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime);
@@ -172,6 +180,32 @@ void BKE_object_tfm_protected_restore(struct Object *ob,
const ObjectTfmProtectedChannels *obtfm,
const short protectflag);
+/* Dependency graph evaluation callbacks. */
+void BKE_object_eval_local_transform(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_parent(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ 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);
+void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx,
struct Scene *scene, struct Object *ob,
@@ -183,7 +217,9 @@ int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float *
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
-struct KeyBlock *BKE_object_insert_shape_key(struct Object *ob, const char *name, const bool from_mix);
+struct KeyBlock *BKE_object_shapekey_insert(struct Object *ob, const char *name, const bool from_mix);
+bool BKE_object_shapekey_remove(struct Main *bmain, struct Object *ob, struct KeyBlock *kb);
+bool BKE_object_shapekey_free(struct Main *bmain, struct Object *ob);
bool BKE_object_flag_test_recursive(const struct Object *ob, short flag);
@@ -222,6 +258,8 @@ void BKE_object_groups_clear(struct Scene *scene, struct Base *base,
struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
+bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index b750d8b283a..9b1b937febf 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -74,13 +74,14 @@ typedef struct OceanCache {
#define OCEAN_CACHING 1
#define OCEAN_CACHED 2
-struct Ocean *BKE_add_ocean(void);
-void BKE_free_ocean_data(struct Ocean *oc);
-void BKE_free_ocean(struct Ocean *oc);
+struct Ocean *BKE_ocean_add(void);
+void BKE_ocean_free_data(struct Ocean *oc);
+void BKE_ocean_free(struct Ocean *oc);
-void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
- float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed);
-void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount);
+void BKE_ocean_init(
+ struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
+ float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed);
+void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount);
/* sampling the ocean surface */
float BKE_ocean_jminus_to_foam(float jminus, float coverage);
@@ -92,16 +93,17 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
/* ocean cache handling */
-struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase,
- int start, int end, float wave_scale,
- float chop_amount, float foam_coverage, float foam_fade, int resolution);
-void BKE_simulate_ocean_cache(struct OceanCache *och, int frame);
+struct OceanCache *BKE_ocean_init_cache(
+ const char *bakepath, const char *relbase,
+ int start, int end, float wave_scale,
+ float chop_amount, float foam_coverage, float foam_fade, int resolution);
+void BKE_ocean_simulate_cache(struct OceanCache *och, int frame);
-void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data);
+void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data);
void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v);
void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j);
-void BKE_free_ocean_cache(struct OceanCache *och);
+void BKE_ocean_free_cache(struct OceanCache *och);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h
index 54deef1ce2f..454edb40c4e 100644
--- a/source/blender/blenkernel/BKE_treehash.h
+++ b/source/blender/blenkernel/BKE_outliner_treehash.h
@@ -19,34 +19,33 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BKE_TREEHASH_H__
-#define __BKE_TREEHASH_H__
+#ifndef __BKE_OUTLINER_TREEHASH_H__
+#define __BKE_OUTLINER_TREEHASH_H__
-/** \file BKE_treehash.h
+/** \file BKE_outliner_treehash.h
* \ingroup bke
*/
struct ID;
-struct GHash;
struct BLI_mempool;
struct TreeStoreElem;
/* create and fill hashtable with treestore elements */
-void *BKE_treehash_create_from_treestore(struct BLI_mempool *treestore);
+void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore);
/* full rebuild for already allocated hashtable */
-void *BKE_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
+void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
/* full rebuild for already allocated hashtable */
-void BKE_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
+void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
/* find first unused element with specific type, nr and id */
-struct TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
+struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
/* find user or unused element with specific type, nr and id */
-struct TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id);
+struct TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id);
/* free treehash structure */
-void BKE_treehash_free(void *treehash);
+void BKE_outliner_treehash_free(void *treehash);
#endif
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8fab44121de..a2397922061 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -48,7 +48,7 @@ struct PackedFile *dupPackedFile(const struct PackedFile *pf_src);
struct PackedFile *newPackedFile(struct ReportList *reports, const char *filename, const char *relabase);
struct PackedFile *newPackedFileMemory(void *mem, int memlen);
-void packAll(struct Main *bmain, struct ReportList *reports);
+void packAll(struct Main *bmain, struct ReportList *reports, bool verbose);
void packLibraries(struct Main *bmain, struct ReportList *reports);
/* unpack */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 3e4e6ab4146..09ccc3dced7 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -37,12 +37,10 @@ struct BMesh;
struct BMFace;
struct Brush;
struct CurveMapping;
-struct MDisps;
struct MeshElemMap;
struct GridPaintMask;
struct Main;
struct MFace;
-struct MultireModifierData;
struct MVert;
struct Object;
struct Paint;
@@ -57,7 +55,6 @@ struct StrokeCache;
struct Tex;
struct ImagePool;
struct UnifiedPaintSettings;
-struct wmOperator;
enum OverlayFlags;
@@ -103,7 +100,7 @@ struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
-void BKE_palette_cleanup(struct Palette *palette);
+void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
@@ -123,6 +120,7 @@ void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
+void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index);
void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil);
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil);
@@ -146,6 +144,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
/* stroke related */
void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]);
+void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation);
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
@@ -158,7 +157,6 @@ typedef struct SculptSession {
struct MPoly *mpoly;
struct MLoop *mloop;
int totvert, totpoly;
- float (*face_normals)[3];
struct KeyBlock *kb;
float *vmask;
@@ -197,8 +195,8 @@ typedef struct SculptSession {
struct StrokeCache *cache;
} SculptSession;
-void BKE_free_sculptsession(struct Object *ob);
-void BKE_free_sculptsession_deformMats(struct SculptSession *ss);
+void BKE_sculptsession_free(struct Object *ob);
+void BKE_sculptsession_free_deformMats(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 0f1389bfeec..e03789f502b 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -45,10 +45,8 @@ struct ParticleSystemModifierData;
struct ParticleSystem;
struct ParticleKey;
struct ParticleSettings;
-struct HairKey;
struct Main;
-struct Group;
struct Object;
struct Scene;
struct DerivedMesh;
@@ -57,12 +55,10 @@ struct MTFace;
struct MCol;
struct MFace;
struct MVert;
-struct IpoCurve;
struct LatticeDeformData;
struct LinkNode;
struct KDTree;
struct RNG;
-struct SurfaceModifierData;
struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
@@ -361,7 +357,7 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct Pa
void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim);
void psys_thread_context_free(struct ParticleThreadContext *ctx);
-void psys_tasks_create(struct ParticleThreadContext *ctx, int totpart, struct ParticleTask **r_tasks, int *r_numtasks);
+void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int endpart, struct ParticleTask **r_tasks, int *r_numtasks);
void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
@@ -463,4 +459,12 @@ typedef struct ParticleRenderData {
#define DMCACHE_NOTFOUND -1
#define DMCACHE_ISCHILD -2
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
+ struct Object *ob,
+ struct ParticleSystem *psys);
+
#endif
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index c8c693fc342..227994b73ee 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -34,8 +34,6 @@ struct CCGElem;
struct CCGKey;
struct CustomData;
struct DMFlagMat;
-struct DMGridAdjacency;
-struct GHash;
struct MFace;
struct MVert;
struct PBVH;
@@ -64,7 +62,7 @@ PBVH *BKE_pbvh_new(void);
void BKE_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts,
int totface, int totvert, struct CustomData *vdata);
void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
- struct DMGridAdjacency *gridadj, int totgrid,
+ int totgrid,
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);
@@ -105,8 +103,9 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
-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_raycast_project_ray_root(
+ PBVH *bvh, bool original,
+ float ray_start[3], float ray_end[3], float ray_normal[3]);
/* Drawing */
@@ -122,6 +121,7 @@ typedef enum {
} PBVHType;
PBVHType BKE_pbvh_type(const PBVH *bvh);
+bool BKE_pbvh_has_faces(const PBVH *bvh);
/* Get the PBVH root's bounding box */
void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]);
@@ -144,8 +144,10 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], float radius);
+bool BKE_pbvh_bmesh_update_topology(
+ PBVH *bvh, PBVHTopologyUpdateMode mode,
+ const float center[3], const float view_normal[3],
+ float radius);
/* Node Access */
@@ -173,7 +175,7 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
- struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj);
+ struct CCGElem ***grid_elems);
void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node,
int *uniquevert, int *totvert);
void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
@@ -201,7 +203,7 @@ void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems,
- struct DMGridAdjacency *gridadj, void **gridfaces,
+ void **gridfaces,
struct DMFlagMat *flagmats, unsigned int **grid_hidden);
/* Layer displacement */
@@ -334,6 +336,9 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode);
+void BKE_pbvh_node_get_bm_orco_data(
+ PBVHNode *node,
+ int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3]);
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index e18e9d46a25..a3ffad1f66b 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -303,7 +303,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, struct ListBase *ptcaches_old, bool copy_data);
+struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data);
/********************** Baking *********************/
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index c946f3ac9e8..b327f0c2574 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -39,7 +39,6 @@ struct RigidBodyOb;
struct Scene;
struct Object;
-struct Group;
/* -------------- */
/* Memory Management */
@@ -99,4 +98,19 @@ void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
+/* -------------------- */
+/* Depsgraph evaluation */
+
+struct EvaluationContext;
+
+void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx,
+ struct Scene *scene);
+
+void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx,
+ struct Scene *scene);
+
+void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+
#endif /* __BKE_RIGIDBODY_H__ */
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index d598a26fdf9..ebdd159b40c 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -31,7 +31,6 @@
* \ingroup bke
*/
-struct Text;
struct bSensor;
struct Object;
struct bController;
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 149472db8fa..027bdbbbe58 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -39,16 +39,13 @@ extern "C" {
struct AviCodecData;
struct Base;
-struct DisplaySafeAreas;
struct EvaluationContext;
-struct bglMats;
struct Main;
struct Object;
struct QuicktimeCodecData;
struct RenderData;
struct SceneRenderLayer;
struct Scene;
-struct Text;
struct UnitSettings;
struct Main;
@@ -73,6 +70,7 @@ void BKE_scene_free(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
/* base functions */
+struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
@@ -113,8 +111,8 @@ char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame);
/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
-float BKE_scene_frame_get(struct Scene *scene);
-float BKE_scene_frame_get_from_ctime(struct Scene *scene, const float frame);
+float BKE_scene_frame_get(const struct Scene *scene);
+float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float frame);
void BKE_scene_frame_set(struct Scene *scene, double cfra);
/* ** Scene evaluation ** */
@@ -125,16 +123,20 @@ void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct
struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
+struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
+bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
+
/* render profile */
-int get_render_subsurf_level(struct RenderData *r, int level);
-int get_render_child_particle_number(struct RenderData *r, int num);
-int get_render_shadow_samples(struct RenderData *r, int samples);
-float get_render_aosss_error(struct RenderData *r, float error);
+int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render);
+int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
+int get_render_shadow_samples(const struct RenderData *r, int samples);
+float get_render_aosss_error(const struct RenderData *r, float error);
-bool BKE_scene_use_new_shading_nodes(struct Scene *scene);
+bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
+bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
-bool BKE_scene_uses_blender_internal(struct Scene *scene);
-bool BKE_scene_uses_blender_game(struct Scene *scene);
+bool BKE_scene_uses_blender_internal(const struct Scene *scene);
+bool BKE_scene_uses_blender_game(const struct Scene *scene);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -145,6 +147,23 @@ int BKE_render_num_threads(const struct RenderData *r);
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
+/* multiview */
+bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv);
+bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
+size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd);
+struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id);
+const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id);
+size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
+void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath);
+void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath);
+const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id);
+void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, const char **rext);
+void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
+size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 29590c52b23..48616418e67 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -47,7 +47,6 @@ struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;
-struct uiMenuItem;
struct wmKeyConfig;
struct wmNotifier;
struct wmWindow;
@@ -274,6 +273,9 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
+void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *));
+void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
@@ -281,6 +283,7 @@ void BKE_screen_area_free(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
@@ -290,6 +293,8 @@ unsigned int BKE_screen_view3d_layer_active_ex(
unsigned int BKE_screen_view3d_layer_active(
const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2);
+unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
void BKE_screen_view3d_scene_sync(struct bScreen *sc);
void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index c936ce5284d..f73548373ef 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -38,11 +38,10 @@ struct GSet;
struct ImBuf;
struct Main;
struct Mask;
-struct MovieClip;
struct Scene;
struct Sequence;
struct SequenceModifierData;
-struct Strip;
+struct Stereo3dFormat;
struct StripElem;
struct bSound;
@@ -101,6 +100,7 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
+ size_t view_id;
} SeqRenderData;
void BKE_sequencer_new_render_data(
@@ -225,6 +225,7 @@ void BKE_sequencer_base_clipboard_pointers_store(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq);
@@ -237,7 +238,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list);
+void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@@ -295,7 +296,7 @@ int BKE_sequence_effect_get_supports_mask(int seq_type);
* Sequencer editing functions
* **********************************************************************
*/
-
+
/* for transform but also could use elsewhere */
int BKE_sequence_tx_get_final_left(struct Sequence *seq, bool metaclip);
int BKE_sequence_tx_get_final_right(struct Sequence *seq, bool metaclip);
@@ -357,6 +358,10 @@ typedef struct SeqLoadInfo {
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
+ /* multiview */
+ char views_format;
+ struct Stereo3dFormat *stereo3d_format;
+
/* return values */
char name[64];
struct Sequence *seq_sound; /* for movie's */
@@ -401,7 +406,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
/* view3d draw callback, run when not in background view */
-typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]);
+typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
@@ -435,7 +440,7 @@ typedef struct SequenceModifierTypeInfo {
void (*apply) (struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask);
} SequenceModifierTypeInfo;
-struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type);
+const struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type);
struct SequenceModifierData *BKE_sequence_modifier_new(struct Sequence *seq, const char *name, int type);
bool BKE_sequence_modifier_remove(struct Sequence *seq, struct SequenceModifierData *smd);
@@ -449,7 +454,9 @@ void BKE_sequence_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq
int BKE_sequence_supports_modifiers(struct Sequence *seq);
/* internal filters */
-struct ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id, int cfra, bool make_float);
+struct ImBuf *BKE_sequencer_render_mask_input(
+ const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id,
+ int cfra, int fra_offset, bool make_float);
void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, bool make_float, struct ImBuf *mask_input);
#endif /* __BKE_SEQUENCER_H__ */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 070cd4a9cf0..070f5c762db 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -47,7 +47,6 @@
*/
struct Object;
-struct Scene;
struct DerivedMesh;
struct MVert;
struct MDeformVert;
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index a4182b8405f..819b49da8e9 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -35,9 +35,7 @@
#define SOUND_WAVE_SAMPLES_PER_SECOND 250
-struct PackedFile;
struct bSound;
-struct ListBase;
struct Main;
struct Sequence;
@@ -46,98 +44,98 @@ typedef struct SoundWaveform {
float *data;
} SoundWaveform;
-void sound_init_once(void);
-void sound_exit_once(void);
+void BKE_sound_init_once(void);
+void BKE_sound_exit_once(void);
-void sound_init(struct Main *main);
+void BKE_sound_init(struct Main *main);
-void sound_init_main(struct Main *bmain);
+void BKE_sound_init_main(struct Main *bmain);
-void sound_exit(void);
+void BKE_sound_exit(void);
-void sound_force_device(int device);
-int sound_define_from_str(const char *str);
+void BKE_sound_force_device(int device);
+int BKE_sound_define_from_str(const char *str);
-struct bSound *sound_new_file(struct Main *main, const char *filename);
+struct bSound *BKE_sound_new_file(struct Main *main, const char *filename);
// XXX unused currently
#if 0
-struct bSound *sound_new_buffer(struct Main *bmain, struct bSound *source);
+struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source);
-struct bSound *sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
+struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
#endif
-void sound_delete(struct Main *bmain, struct bSound *sound);
+void BKE_sound_delete(struct Main *bmain, struct bSound *sound);
-void sound_cache(struct bSound *sound);
+void BKE_sound_cache(struct bSound *sound);
-void sound_delete_cache(struct bSound *sound);
+void BKE_sound_delete_cache(struct bSound *sound);
-void sound_load(struct Main *main, struct bSound *sound);
+void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
#ifdef __AUD_C_API_H__
-AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
+AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
-void sound_create_scene(struct Scene *scene);
+void BKE_sound_create_scene(struct Scene *scene);
-void sound_destroy_scene(struct Scene *scene);
+void BKE_sound_destroy_scene(struct Scene *scene);
-void sound_mute_scene(struct Scene *scene, int muted);
+void BKE_sound_mute_scene(struct Scene *scene, int muted);
-void sound_update_fps(struct Scene *scene);
+void BKE_sound_update_fps(struct Scene *scene);
-void sound_update_scene_listener(struct Scene *scene);
+void BKE_sound_update_scene_listener(struct Scene *scene);
-void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
-void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
-void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
+void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void sound_remove_scene_sound(struct Scene *scene, void *handle);
+void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle);
-void sound_mute_scene_sound(void *handle, char mute);
+void BKE_sound_mute_scene_sound(void *handle, char mute);
-void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip);
-void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip);
+void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void sound_update_scene_sound(void *handle, struct bSound *sound);
+void BKE_sound_update_scene_sound(void *handle, struct bSound *sound);
-void sound_set_cfra(int cfra);
+void BKE_sound_set_cfra(int cfra);
-void sound_set_scene_volume(struct Scene *scene, float volume);
+void BKE_sound_set_scene_volume(struct Scene *scene, float volume);
-void sound_set_scene_sound_volume(void *handle, float volume, char animated);
+void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated);
-void sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
+void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
-void sound_set_scene_sound_pan(void *handle, float pan, char animated);
+void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated);
-void sound_update_sequencer(struct Main *main, struct bSound *sound);
+void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound);
-void sound_play_scene(struct Scene *scene);
+void BKE_sound_play_scene(struct Scene *scene);
-void sound_stop_scene(struct Scene *scene);
+void BKE_sound_stop_scene(struct Scene *scene);
-void sound_seek_scene(struct Main *bmain, struct Scene *scene);
+void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene);
-float sound_sync_scene(struct Scene *scene);
+float BKE_sound_sync_scene(struct Scene *scene);
-int sound_scene_playing(struct Scene *scene);
+int BKE_sound_scene_playing(struct Scene *scene);
-void sound_free_waveform(struct bSound *sound);
+void BKE_sound_free_waveform(struct bSound *sound);
-void sound_read_waveform(struct bSound *sound, short *stop);
+void BKE_sound_read_waveform(struct bSound *sound, short *stop);
-void sound_update_scene(struct Main *bmain, struct Scene *scene);
+void BKE_sound_update_scene(struct Main *bmain, struct Scene *scene);
-void *sound_get_factory(void *sound);
+void *BKE_sound_get_factory(void *sound);
-float sound_get_length(struct bSound *sound);
+float BKE_sound_get_length(struct bSound *sound);
-bool sound_is_jack_supported(void);
+bool BKE_sound_is_jack_supported(void);
#endif /* __BKE_SOUND_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 3dae4087866..c1c96c8228c 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -41,17 +41,14 @@ struct DerivedMesh;
struct MeshElemMap;
struct Mesh;
struct MPoly;
-struct MultiresSubsurf;
struct Object;
struct PBVH;
struct SubsurfModifierData;
struct CCGEdge;
struct CCGFace;
-struct CCGSubsurf;
struct CCGVert;
struct EdgeHash;
struct PBVH;
-struct DMGridAdjacency;
/**************************** External *****************************/
@@ -120,7 +117,6 @@ typedef struct CCGDerivedMesh {
int *pmap_mem;
struct CCGElem **gridData;
- struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
struct CCGFace **gridFaces;
struct DMFlagMat *gridFlagMats;
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 96e88f80464..a5a59d14c92 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -40,14 +40,13 @@ extern "C" {
struct Main;
struct Text;
struct TextLine;
-struct SpaceText;
void BKE_text_free (struct Text *text);
void txt_set_undostate (int u);
int txt_get_undostate (void);
struct Text *BKE_text_add (struct Main *bmain, const char *name);
int txt_extended_ascii_as_utf8(char **str);
-int BKE_text_reload (struct Text *text);
+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);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index ebf85ff51d1..4e5214bc364 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,9 +42,7 @@ struct Brush;
struct ColorBand;
struct EnvMap;
struct FreestyleLineStyle;
-struct HaloRen;
struct Lamp;
-struct LampRen;
struct Main;
struct Material;
struct MTex;
@@ -61,8 +59,6 @@ struct World;
#define MAXCOLORBAND 32
-void BKE_texture_free(struct Tex *t);
-
void init_colorband(struct ColorBand *coba, bool rangetype);
struct ColorBand *add_colorband(bool rangetype);
bool do_colorband(const struct ColorBand *coba, float in, float out[4]);
@@ -71,15 +67,17 @@ struct CBData *colorband_element_add(struct ColorBand *coba, float position);
int colorband_element_remove(struct ColorBand *coba, int index);
void colorband_update_sort(struct ColorBand *coba);
-void default_tex(struct Tex *tex);
-struct Tex *add_texture(struct Main *bmain, const char *name);
-void tex_set_type(struct Tex *tex, int type);
-void default_mtex(struct MTex *mtex);
-struct MTex *add_mtex(void);
-struct MTex *add_mtex_id(struct ID *id, int slot);
-struct Tex *BKE_texture_copy(struct Tex *tex);
-struct Tex *localize_texture(struct Tex *tex);
-void BKE_texture_make_local(struct Tex *tex);
+void BKE_texture_free(struct Tex *tex);
+void BKE_texture_default(struct Tex *tex);
+struct Tex *BKE_texture_copy(struct Tex *tex);
+struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
+struct Tex *BKE_texture_localize(struct Tex *tex);
+void BKE_texture_make_local(struct Tex *tex);
+void BKE_texture_type_set(struct Tex *tex, int type);
+
+void BKE_texture_mtex_default(struct MTex *mtex);
+struct MTex *BKE_texture_mtex_add(void);
+struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
/* UNUSED */
// void autotexname(struct Tex *tex);
@@ -105,36 +103,38 @@ void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex
bool has_current_material_texture(struct Material *ma);
-struct TexMapping *add_tex_mapping(int type);
-void default_tex_mapping(struct TexMapping *texmap, int type);
-void init_tex_mapping(struct TexMapping *texmap);
+struct TexMapping *BKE_texture_mapping_add(int type);
+void BKE_texture_mapping_default(struct TexMapping *texmap, int type);
+void BKE_texture_mapping_init(struct TexMapping *texmap);
+
+struct ColorMapping *BKE_texture_colormapping_add(void);
+void BKE_texture_colormapping_default(struct ColorMapping *colormap);
-struct ColorMapping *add_color_mapping(void);
-void default_color_mapping(struct ColorMapping *colormap);
+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);
-void BKE_free_envmapdata(struct EnvMap *env);
-void BKE_free_envmap(struct EnvMap *env);
-struct EnvMap *BKE_add_envmap(void);
-struct EnvMap *BKE_copy_envmap(struct EnvMap *env);
+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);
-void BKE_free_pointdensitydata(struct PointDensity *pd);
-void BKE_free_pointdensity(struct PointDensity *pd);
-struct PointDensity *BKE_add_pointdensity(void);
-struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd);
+void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
+void BKE_texture_voxeldata_free(struct VoxelData *vd);
+struct VoxelData *BKE_texture_voxeldata_add(void);
+struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd);
-void BKE_free_voxeldatadata(struct VoxelData *vd);
-void BKE_free_voxeldata(struct VoxelData *vd);
-struct VoxelData *BKE_add_voxeldata(void);
-struct VoxelData *BKE_copy_voxeldata(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);
-void BKE_free_oceantex(struct OceanTex *ot);
-struct OceanTex *BKE_add_oceantex(void);
-struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot);
-
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
-void BKE_texture_get_value(struct Scene *scene, struct Tex *texture, float *tex_co, struct TexResult *texres, 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);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index e5fb60cf1b5..b03a234e1e7 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -41,7 +41,6 @@ struct MovieTrackingMarker;
struct MovieTrackingPlaneTrack;
struct MovieTrackingPlaneMarker;
struct MovieTracking;
-struct MovieTrackingContext;
struct MovieTrackingObject;
struct MovieClipUser;
struct MovieDistortion;
@@ -91,7 +90,7 @@ struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tr
struct MovieTrackingObject *object,
const char *name);
struct MovieTrackingTrack *BKE_tracking_track_get_indexed(struct MovieTracking *tracking, int tracknr,
- struct ListBase **tracksbase_r);
+ struct ListBase **r_tracksbase);
struct MovieTrackingTrack *BKE_tracking_track_get_active(struct MovieTracking *tracking);
@@ -137,6 +136,21 @@ struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct Movie
void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base);
+bool BKE_tracking_plane_track_has_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *track);
+bool BKE_tracking_plane_track_remove_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *track);
+
+void BKE_tracking_plane_tracks_remove_point_track(struct MovieTracking *tracking,
+ struct MovieTrackingTrack *track);
+
+void BKE_tracking_plane_track_replace_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *old_track,
+ struct MovieTrackingTrack *new_track);
+void BKE_tracking_plane_tracks_replace_point_track(struct MovieTracking *tracking,
+ struct MovieTrackingTrack *old_track,
+ struct MovieTrackingTrack *new_track);
+
/* **** Plane Marker **** */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track,
struct MovieTrackingPlaneMarker *plane_marker);
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 78875951ca4..ca295c51f5d 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -43,16 +43,20 @@ struct ReportList;
struct Scene;
typedef struct bMovieHandle {
- int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
- int (*append_movie)(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
- void (*end_movie)(void);
- int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */
- void (*get_movie_path)(char *string, struct RenderData *rd); /* optional */
+ int (*start_movie)(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+ int (*append_movie)(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_movie)(void *context_v);
+ int (*get_next_frame)(void *context_v, struct RenderData *rd, struct ReportList *reports); /* optional */
+ void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); /* optional */
+ void *(*context_create)(void);
+ void (*context_free)(void *context_v);
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
-void BKE_movie_filepath_get(char *string, struct RenderData *rd);
+void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
+void BKE_context_create(bMovieHandle *mh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 703e84b3798..a40c31022e3 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -64,16 +64,15 @@ enum {
FFMPEG_PRESET_XVID = 7,
};
-struct IDProperty;
struct RenderData;
struct ReportList;
struct Scene;
-int BKE_ffmpeg_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
-void BKE_ffmpeg_end(void);
-int BKE_ffmpeg_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd);
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix);
+void BKE_ffmpeg_end(void *context_v);
+int BKE_ffmpeg_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
@@ -83,6 +82,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
+void *BKE_ffmpeg_context_create(void);
+void BKE_ffmpeg_context_free(void *context_v);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
index bdce9abe8ad..0837e9bce79 100644
--- a/source/blender/blenkernel/BKE_writeframeserver.h
+++ b/source/blender/blenkernel/BKE_writeframeserver.h
@@ -40,11 +40,16 @@ struct RenderData;
struct ReportList;
struct Scene;
-int BKE_frameserver_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
-void BKE_frameserver_end(void);
-int BKE_frameserver_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-int BKE_frameserver_loop(struct RenderData *rd, struct ReportList *reports);
+int BKE_frameserver_start(
+ void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+void BKE_frameserver_end(void *context_v);
+int BKE_frameserver_append(
+ void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
+void *BKE_frameserver_context_create(void);
+void BKE_frameserver_context_free(void *context_v);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index a826fe26e68..37e5b36779f 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../blenfont
../blenlib
../blenloader
+ ../depsgraph
../gpu
../ikplugin
../imbuf
@@ -67,6 +68,7 @@ set(SRC
intern/anim_sys.c
intern/appdir.c
intern/armature.c
+ intern/armature_update.c
intern/autoexec.c
intern/blender.c
intern/bmfont.c
@@ -119,6 +121,7 @@ set(SRC
intern/mask_rasterize.c
intern/material.c
intern/mball.c
+ intern/mball_tessellate.c
intern/mesh.c
intern/mesh_evaluate.c
intern/mesh_mapping.c
@@ -133,7 +136,9 @@ set(SRC
intern/object.c
intern/object_deform.c
intern/object_dupli.c
+ intern/object_update.c
intern/ocean.c
+ intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
intern/particle.c
@@ -171,7 +176,6 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
- intern/treehash.c
intern/unit.c
intern/world.c
intern/writeavi.c
@@ -210,6 +214,8 @@ set(SRC
BKE_depsgraph.h
BKE_displist.h
BKE_dynamicpaint.h
+ BKE_editmesh.h
+ BKE_editmesh_bvh.h
BKE_effect.h
BKE_fcurve.h
BKE_fluidsim.h
@@ -233,6 +239,7 @@ set(SRC
BKE_mask.h
BKE_material.h
BKE_mball.h
+ BKE_mball_tessellate.h
BKE_mesh.h
BKE_mesh_mapping.h
BKE_mesh_remap.h
@@ -244,6 +251,7 @@ set(SRC
BKE_object.h
BKE_object_deform.h
BKE_ocean.h
+ BKE_outliner_treehash.h
BKE_packedFile.h
BKE_paint.h
BKE_particle.h
@@ -264,12 +272,9 @@ set(SRC
BKE_speaker.h
BKE_subsurf.h
BKE_suggestions.h
- BKE_editmesh.h
- BKE_editmesh_bvh.h
BKE_text.h
BKE_texture.h
BKE_tracking.h
- BKE_treehash.h
BKE_unit.h
BKE_utildefines.h
BKE_world.h
@@ -478,4 +483,8 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 47bba5f5537..9d19e1c29b4 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -58,6 +58,7 @@ incs = [
'../blenlib',
'../blenloader',
'../bmesh',
+ '../depsgraph',
'../gpu',
'../ikplugin',
'../imbuf',
@@ -175,6 +176,9 @@ if env['WITH_BF_BINRELOC']:
incs += ' #extern/binreloc/include'
defs.append('WITH_BINRELOC')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') )
else:
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 0bfa3628967..22d450d5767 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -295,11 +295,11 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
- fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
@@ -412,7 +412,7 @@ void DM_ensure_tessface(DerivedMesh *dm)
/* printf("info %s: polys -> ngons calculated\n", __func__); */
}
else {
- printf("warning %s: could not create tessfaces from %d polygons, dm->type=%d\n",
+ printf("warning %s: could not create tessfaces from %d polygons, dm->type=%u\n",
__func__, numPolys, dm->type);
}
}
@@ -931,7 +931,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
ModifierData *md, int build_shapekey_layers)
{
Mesh *me = ob->data;
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm;
KeyBlock *kb;
@@ -1011,8 +1011,9 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr
ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest);
- if (kb->data)
+ if (kb && kb->data) {
return kb->data;
+ }
}
return NULL;
@@ -1131,7 +1132,7 @@ typedef struct DMWeightColorInfo {
} DMWeightColorInfo;
-static int dm_drawflag_calc(ToolSettings *ts)
+static int dm_drawflag_calc(const ToolSettings *ts)
{
return ((ts->multipaint ? CALC_WP_MULTIPAINT :
/* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL*/
@@ -1275,7 +1276,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d
else {
weightpaint_color(col, dm_wcinfo, 0.0f);
}
- fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
+ copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
}
}
@@ -1368,7 +1369,7 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
}
}
-static void DM_update_statvis_color(Scene *scene, Object *ob, DerivedMesh *dm)
+static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -1585,7 +1586,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* Apply all leading deforming modifiers */
for (; md; md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1639,7 +1640,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
clothorcodm = NULL;
for (; md; md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1938,7 +1939,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
}
- {
+ if (sculpt_dyntopo == false) {
DM_ensure_tessface(finaldm);
/* without this, drawing ngon tri's faces will show ugly tessellated face
@@ -2000,7 +2001,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
if (!modifier_isEnabled(scene, md, required_mode)) return 0;
@@ -2059,7 +2060,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
curr = datamasks;
for (i = 0; md; i++, md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -2291,13 +2292,8 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
}
static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
- int build_shapekey_layers)
+ int build_shapekey_layers, int needMapping)
{
- Object *obact = scene->basact ? scene->basact->object : NULL;
- bool editing = BKE_paint_select_face_test(ob);
- /* weight paint and face select need original indices because of selection buffer drawing */
- int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)));
-
BLI_assert(ob->type == OB_MESH);
BKE_object_free_derived_caches(ob);
@@ -2312,6 +2308,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
ob->lastDataMask = dataMask;
+ ob->lastNeedMapping = needMapping;
if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
@@ -2340,14 +2337,23 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS));
}
-static CustomDataMask object_get_datamask(Scene *scene, Object *ob)
+static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, int *r_needmapping)
{
Object *actob = scene->basact ? scene->basact->object : NULL;
CustomDataMask mask = ob->customdata_mask;
+ bool editing = BKE_paint_select_face_test(ob);
+
+ if (r_needmapping)
+ *r_needmapping = 0;
if (ob == actob) {
+
+ /* weight paint and face select need original indices because of selection buffer drawing */
+ if (r_needmapping)
+ *r_needmapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
+
/* check if we need tfaces & mcols due to face select or texture paint */
- if (BKE_paint_select_face_test(ob) || (ob->mode & OB_MODE_TEXTURE_PAINT)) {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
}
@@ -2370,13 +2376,14 @@ static CustomDataMask object_get_datamask(Scene *scene, Object *ob)
void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, int build_shapekey_layers)
{
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
if (em) {
editbmesh_build_data(scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers);
+ mesh_build_data(scene, ob, dataMask, build_shapekey_layers, needMapping);
}
}
@@ -2387,10 +2394,11 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
- if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask || (needMapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needMapping);
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
@@ -2401,10 +2409,12 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needmapping;
+
+ dataMask |= object_get_datamask(scene, ob, &needmapping);
- if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask || (needmapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needmapping);
return ob->derivedDeform;
}
@@ -2493,7 +2503,7 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit,
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
@@ -2511,7 +2521,7 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index f9556bf39ab..1b73978b524 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -54,6 +54,7 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -716,6 +717,57 @@ void BKE_pose_channels_hash_free(bPose *pose)
}
/**
+ * Selectively remove pose channels.
+ */
+void BKE_pose_channels_remove(
+ Object *ob,
+ bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
+{
+ /* First erase any associated pose channel */
+ if (ob->pose) {
+ bPoseChannel *pchan, *pchan_next;
+ bConstraint *con;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan_next) {
+ pchan_next = pchan->next;
+
+ if (filter_fn(pchan->name, user_data)) {
+ BKE_pose_channel_free(pchan);
+ if (ob->pose->chanhash) {
+ BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
+ }
+ BLI_freelinkN(&ob->pose->chanbase, pchan);
+ }
+ else {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob) {
+ if (ct->subtarget[0]) {
+ if (filter_fn(ct->subtarget, user_data)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ ct->subtarget[0] = 0;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
* Deallocates a pose channel.
* Does not free the pose channel itself.
*/
@@ -929,6 +981,12 @@ void BKE_pose_update_constraint_flags(bPose *pose)
pchan->constflag |= PCHAN_HAS_CONST;
}
}
+ pose->flag &= ~POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
+}
+
+void BKE_pose_tag_update_constraint_flags(bPose *pose)
+{
+ pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
/* Clears all BONE_UNKEYED flags for every pose channel in every pose
@@ -1311,6 +1369,16 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
+/* Tag pose for recalc. Also tag all related data to be recalc. */
+void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
+{
+ pose->flag |= POSE_RECALC;
+ /* Depsgraph components depends on actual pose state,
+ * if pose was changed depsgraph is to be updated as well.
+ */
+ DAG_relations_tag_update(bmain);
+}
+
/* For the calculation of the effects of an Action at the given frame on an object
* This is currently only used for the Action Constraint
*/
diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c
index 28667d458b8..811461b84c1 100644
--- a/source/blender/blenkernel/intern/addon.c
+++ b/source/blender/blenkernel/intern/addon.c
@@ -62,12 +62,12 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet)
void BKE_addon_pref_type_add(bAddonPrefType *apt)
{
- BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt);
+ BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt);
}
-void BKE_addon_pref_type_remove(bAddonPrefType *apt)
+void BKE_addon_pref_type_remove(const bAddonPrefType *apt)
{
- BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, MEM_freeN);
+ BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN);
}
void BKE_addon_pref_type_init(void)
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index effe32a8079..d5a8b8f857c 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -134,7 +134,7 @@ AnimData *BKE_animdata_from_id(ID *id)
* the AnimData pointer is stored immediately after the given ID-block in the struct,
* as per IdAdtTemplate. Also note that
*/
-AnimData *BKE_id_add_animdata(ID *id)
+AnimData *BKE_animdata_add_id(ID *id)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate, and add the AnimData
@@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Freeing -------------------------------------------- */
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_free_animdata(ID *id)
+void BKE_animdata_free(ID *id)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
@@ -253,7 +253,7 @@ void BKE_free_animdata(ID *id)
/* Copying -------------------------------------------- */
/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action)
+AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
{
AnimData *dadt;
@@ -285,25 +285,25 @@ AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_copy_animdata_id(ID *id_to, ID *id_from, const bool do_action)
+bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
{
AnimData *adt;
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_free_animdata(id_to);
+ BKE_animdata_free(id_to);
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_copy_animdata(adt, do_action);
+ iat->adt = BKE_animdata_copy(adt, do_action);
}
return true;
}
-void BKE_copy_animdata_id_action(ID *id)
+void BKE_animdata_copy_id_action(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -426,7 +426,7 @@ void BKE_animdata_make_local(AnimData *adt)
/* 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_relink_animdata(AnimData *adt)
+void BKE_animdata_relink(AnimData *adt)
{
/* sanity check */
if (adt == NULL)
@@ -571,7 +571,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths
/* get animdata from src, and create for destination (if needed) */
srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_id_add_animdata(dstID);
+ dstAdt = BKE_animdata_add_id(dstID);
if (ELEM(NULL, srcAdt, dstAdt)) {
if (G.debug & G_DEBUG)
@@ -1167,7 +1167,7 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
* i.e. pose.bones["Bone"]
*/
/* TODO: use BKE_animdata_main_cb for looping over all data */
-void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
+void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
{
Main *mainptr = G.main;
ID *id;
@@ -1496,8 +1496,11 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
/* get property to write to */
if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) {
- /* set value - only for animatable numerical values */
- if (RNA_property_animateable(&new_ptr, prop)) {
+ /* set value for animatable numerical values only
+ * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
+ * without an ID provided, which causes the animateable test to fail!
+ */
+ if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) {
int array_len = RNA_property_array_length(&new_ptr, prop);
bool written = false;
@@ -1617,7 +1620,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
}
/* Simple replacement based data-setting of the FCurve using RNA */
-static bool animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
{
char *path = NULL;
bool free_path = false;
@@ -1652,7 +1655,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -1682,7 +1685,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
calculate_fcurve(fcu, ctime);
- ok = animsys_execute_fcurve(ptr, NULL, fcu);
+ ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1751,7 +1754,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -1797,12 +1800,6 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe)
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
{
- /* firstly, analytically generate values for influence and time (if applicable) */
- if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
- strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
- if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
- strip->influence = nlastrip_get_influence(strip, ctime);
-
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
PointerRNA strip_ptr;
@@ -1813,6 +1810,15 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
/* execute these settings as per normal */
animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
}
+
+ /* analytically generate values for influence and time (if applicable)
+ * - we do this after the F-Curves have been evaluated to override the effects of those
+ * in case the override has been turned off.
+ */
+ if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
+ strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
+ if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
+ strip->influence = nlastrip_get_influence(strip, ctime);
/* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped
* to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip
@@ -2840,3 +2846,62 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
}
/* ***************************************** */
+
+/* ************** */
+/* Evaluation API */
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
+ * which should get handled as part of the graph instead...
+ */
+ DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
+ BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+}
+
+void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+ ID *id,
+ FCurve *fcu)
+{
+ /* TODO(sergey): De-duplicate with BKE animsys. */
+ ChannelDriver *driver = fcu->driver;
+ PointerRNA id_ptr;
+ bool ok = false;
+
+ DEBUG_PRINT("%s on %s (%s[%d])\n",
+ __func__,
+ id->name,
+ fcu->rna_path,
+ fcu->array_index);
+
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* check if this driver's curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
+ /* check if driver itself is tagged for recalculation */
+ /* XXX driver recalc flag is not set yet by depsgraph! */
+ if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
+ /* evaluate this using values set already in other places
+ * NOTE: for 'layering' option later on, we should check if we should remove old value before adding
+ * new to only be done when drivers only changed */
+ //printf("\told val = %f\n", fcu->curval);
+ calculate_fcurve(fcu, eval_ctx->ctime);
+ ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+ //printf("\tnew val = %f\n", fcu->curval);
+
+ /* clear recalc flag */
+ driver->flag &= ~DRIVER_FLAG_RECALC;
+
+ /* set error-flag if evaluation failed */
+ if (ok == 0) {
+ printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
+ driver->flag |= DRIVER_FLAG_INVALID;
+ }
+ }
+ }
+}
+
+#undef DEBUG_PRINT
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 60e81003c40..ee6710e1130 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -32,12 +32,11 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
+#include "BKE_blender.h" /* BLENDER_VERSION */
#include "BKE_appdir.h" /* own include */
#include "GHOST_Path-api.h"
-#include "../blenkernel/BKE_blender.h" /* BLENDER_VERSION, bad level include (no function call) */
-
#include "MEM_guardedalloc.h"
#ifdef WIN32
@@ -501,54 +500,6 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
/* Preset paths */
/**
- * Tries appending each of the semicolon-separated extensions in the PATHEXT
- * environment variable (Windows-only) onto *name in turn until such a file is found.
- * Returns success/failure.
- */
-static int add_win32_extension(char *name)
-{
- int retval = 0;
- int type;
-
- type = BLI_exists(name);
- if ((type == 0) || S_ISDIR(type)) {
-#ifdef _WIN32
- char filename[FILE_MAX];
- char ext[FILE_MAX];
- const char *extensions = getenv("PATHEXT");
- if (extensions) {
- char *temp;
- do {
- strcpy(filename, name);
- temp = strstr(extensions, ";");
- if (temp) {
- strncpy(ext, extensions, temp - extensions);
- ext[temp - extensions] = 0;
- extensions = temp + 1;
- strcat(filename, ext);
- }
- else {
- strcat(filename, extensions);
- }
-
- type = BLI_exists(filename);
- if (type && (!S_ISDIR(type))) {
- retval = 1;
- strcpy(name, filename);
- break;
- }
- } while (temp);
- }
-#endif
- }
- else {
- retval = 1;
- }
-
- return (retval);
-}
-
-/**
* Checks if name is a fully qualified filename to an executable.
* If not it searches $PATH for the file. On Windows it also
* adds the correct extension (.com .exe etc) from
@@ -560,41 +511,36 @@ static int add_win32_extension(char *name)
* (must be FILE_MAX minimum)
* \param name The name of the executable (usually argv[0]) to be checked
*/
-static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
+static void where_am_i(char *fullname, const size_t maxlen, const char *name)
{
- char filename[FILE_MAX];
- const char *path = NULL, *temp;
-
-#ifdef _WIN32
- const char *separator = ";";
-#else
- const char *separator = ":";
-#endif
-
-
#ifdef WITH_BINRELOC
/* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
- path = br_find_exe(NULL);
- if (path) {
- BLI_strncpy(fullname, path, maxlen);
- free((void *)path);
- return;
+ {
+ const char *path = NULL;
+ path = br_find_exe(NULL);
+ if (path) {
+ BLI_strncpy(fullname, path, maxlen);
+ free((void *)path);
+ return;
+ }
}
#endif
#ifdef _WIN32
- wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
- if (GetModuleFileNameW(0, fullname_16, maxlen)) {
- conv_utf_16_to_8(fullname_16, fullname, maxlen);
- if (!BLI_exists(fullname)) {
- printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
- MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ {
+ wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
+ if (GetModuleFileNameW(0, fullname_16, maxlen)) {
+ conv_utf_16_to_8(fullname_16, fullname, maxlen);
+ if (!BLI_exists(fullname)) {
+ printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
+ MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ }
+ MEM_freeN(fullname_16);
+ return;
}
+
MEM_freeN(fullname_16);
- return;
}
-
- MEM_freeN(fullname_16);
#endif
/* unix and non linux */
@@ -611,34 +557,19 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name
else
BLI_join_dirfile(fullname, maxlen, wdir, name);
- add_win32_extension(fullname); /* XXX, doesnt respect length */
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else if (BLI_last_slash(name)) {
// full path
BLI_strncpy(fullname, name, maxlen);
- add_win32_extension(fullname);
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else {
- // search for binary in $PATH
- path = getenv("PATH");
- if (path) {
- do {
- temp = strstr(path, separator);
- if (temp) {
- strncpy(filename, path, temp - path);
- filename[temp - path] = 0;
- path = temp + 1;
- }
- else {
- strncpy(filename, path, sizeof(filename));
- }
- BLI_path_append(fullname, maxlen, name);
- if (add_win32_extension(filename)) {
- BLI_strncpy(fullname, filename, maxlen);
- break;
- }
- } while (temp);
- }
+ BLI_path_program_search(fullname, maxlen, name);
}
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
@@ -650,7 +581,7 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name
void BKE_appdir_program_path_init(const char *argv0)
{
- bli_where_am_i(bprogname, sizeof(bprogname), argv0);
+ where_am_i(bprogname, sizeof(bprogname), argv0);
BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
}
@@ -670,6 +601,58 @@ const char *BKE_appdir_program_dir(void)
return bprogdir;
}
+bool BKE_appdir_program_python_search(
+ char *fullpath, const size_t fullpath_len,
+ const int version_major, const int version_minor)
+{
+ const char *basename = "python";
+ char python_ver[16];
+ /* check both possible names */
+ const char *python_names[] = {basename, python_ver};
+ int i;
+
+ bool is_found = false;
+
+ BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
+
+ {
+ const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
+ if (python_bin_dir) {
+
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+
+ if (
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
+#else
+ BLI_exists(fullpath)
+#endif
+ )
+ {
+ is_found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_found == false) {
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
+ is_found = true;
+ break;
+ }
+ }
+ }
+
+ if (is_found == false) {
+ *fullpath = '\0';
+ }
+
+ return is_found;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -681,7 +664,7 @@ const char *BKE_appdir_program_dir(void)
* \param maxlen The size of the fullname buffer
* \param userdir Directory specified in user preferences
*/
-static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
+static void where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
{
/* Clear existing temp dir, if needed. */
BKE_tempdir_session_purge();
@@ -769,7 +752,7 @@ static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxle
*/
void BKE_tempdir_init(char *userdir)
{
- BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
+ where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
;
}
@@ -794,7 +777,7 @@ const char *BKE_tempdir_base(void)
*/
void BKE_tempdir_system_init(char *dir)
{
- BLI_where_is_temp(dir, NULL, FILE_MAX, NULL);
+ where_is_temp(dir, NULL, FILE_MAX, NULL);
}
/**
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 6b67a4e5763..27d3d1c50fb 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -127,7 +127,7 @@ void BKE_armature_free(bArmature *arm)
/* free animation data */
if (arm->adt) {
- BKE_free_animdata(&arm->id);
+ BKE_animdata_free(&arm->id);
arm->adt = NULL;
}
}
@@ -1700,7 +1700,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* constraints - set target ob pointer to own object */
for (con = pchanw.constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1825,9 +1825,12 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */
+#ifdef WITH_LEGACY_DEPSGRAPH
/* the sorting */
+ /* Sorting for new dependnecy graph is done on the scene graph level. */
if (counter > 1)
DAG_pose_sort(ob);
+#endif
ob->pose->flag &= ~POSE_RECALC;
ob->pose->flag |= POSE_WAS_REBUILT;
@@ -1835,494 +1838,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_channels_hash_make(ob->pose);
}
-
-/* ********************** SPLINE IK SOLVER ******************* */
-
-/* Temporary evaluation tree data used for Spline IK */
-typedef struct tSplineIK_Tree {
- struct tSplineIK_Tree *next, *prev;
-
- int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
-
- bool free_points; /* free the point positions array */
- short chainlen; /* number of bones in the chain */
-
- float *points; /* parametric positions for the joints along the curve */
- bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
-
- bPoseChannel *root; /* bone that is the root node of the chain */
-
- bConstraint *con; /* constraint for this chain */
- bSplineIKConstraint *ikData; /* constraint settings for this chain */
-} tSplineIK_Tree;
-
-/* ----------- */
-
-/* Tag the bones in the chain formed by the given bone for IK */
-static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
-{
- bPoseChannel *pchan, *pchanRoot = NULL;
- bPoseChannel *pchanChain[255];
- bConstraint *con = NULL;
- bSplineIKConstraint *ikData = NULL;
- float boneLengths[255], *jointPoints;
- float totLength = 0.0f;
- bool free_joints = 0;
- int segcount = 0;
-
- /* find the SplineIK constraint */
- for (con = pchan_tip->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
- ikData = con->data;
-
- /* target can only be curve */
- if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
- continue;
- /* skip if disabled */
- if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
- continue;
-
- /* otherwise, constraint is ok... */
- break;
- }
- }
- if (con == NULL)
- return;
-
- /* make sure that the constraint targets are ok
- * - this is a workaround for a depsgraph bug...
- */
- if (ikData->tar) {
- /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
- * currently for paths to work it needs to go through the bevlist/displist system (ton)
- */
-
- /* only happens on reload file, but violates depsgraph still... fix! */
- if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- BKE_displist_make_curveTypes(scene, ikData->tar, 0);
-
- /* path building may fail in EditMode after removing verts [#33268]*/
- if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- /* BLI_assert(cu->path != NULL); */
- return;
- }
- }
- }
-
- /* find the root bone and the chain of bones from the root to the tip
- * NOTE: this assumes that the bones are connected, but that may not be true... */
- for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
- /* store this segment in the chain */
- pchanChain[segcount] = pchan;
-
- /* if performing rebinding, calculate the length of the bone */
- boneLengths[segcount] = pchan->bone->length;
- totLength += boneLengths[segcount];
- }
-
- if (segcount == 0)
- return;
- else
- pchanRoot = pchanChain[segcount - 1];
-
- /* perform binding step if required */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
- float segmentLen = (1.0f / (float)segcount);
- int i;
-
- /* setup new empty array for the points list */
- if (ikData->points)
- MEM_freeN(ikData->points);
- ikData->numpoints = ikData->chainlen + 1;
- ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
-
- /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
- ikData->points[0] = 1.0f;
-
- /* perform binding of the joints to parametric positions along the curve based
- * proportion of the total length that each bone occupies
- */
- for (i = 0; i < segcount; i++) {
- /* 'head' joints, traveling towards the root of the chain
- * - 2 methods; the one chosen depends on whether we've got usable lengths
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
- /* 1) equi-spaced joints */
- ikData->points[i + 1] = ikData->points[i] - segmentLen;
- }
- else {
- /* 2) to find this point on the curve, we take a step from the previous joint
- * a distance given by the proportion that this bone takes
- */
- ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
- }
- }
-
- /* spline has now been bound */
- ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
- }
-
- /* disallow negative values (happens with float precision) */
- CLAMP_MIN(ikData->points[segcount], 0.0f);
-
- /* apply corrections for sensitivity to scaling on a copy of the bind points,
- * since it's easier to determine the positions of all the joints beforehand this way
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
- float splineLen, maxScale;
- int i;
-
- /* make a copy of the points array, that we'll store in the tree
- * - although we could just multiply the points on the fly, this approach means that
- * we can introduce per-segment stretchiness later if it is necessary
- */
- jointPoints = MEM_dupallocN(ikData->points);
- free_joints = 1;
-
- /* get the current length of the curve */
- /* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
-
- /* calculate the scale factor to multiply all the path values by so that the
- * bone chain retains its current length, such that
- * maxScale * splineLen = totLength
- */
- maxScale = totLength / splineLen;
-
- /* apply scaling correction to all of the temporary points */
- /* TODO: this is really not adequate enough on really short chains */
- for (i = 0; i < segcount; i++)
- jointPoints[i] *= maxScale;
- }
- else {
- /* just use the existing points array */
- jointPoints = ikData->points;
- free_joints = 0;
- }
-
- /* make a new Spline-IK chain, and store it in the IK chains */
- /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
- {
- /* make new tree */
- tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
- tree->type = CONSTRAINT_TYPE_SPLINEIK;
-
- tree->chainlen = segcount;
-
- /* copy over the array of links to bones in the chain (from tip to root) */
- tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
- memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
-
- /* store reference to joint position array */
- tree->points = jointPoints;
- tree->free_points = free_joints;
-
- /* store references to different parts of the chain */
- tree->root = pchanRoot;
- tree->con = con;
- tree->ikData = ikData;
-
- /* AND! link the tree to the root */
- BLI_addtail(&pchanRoot->siktree, tree);
- }
-
- /* mark root channel having an IK tree */
- pchanRoot->flag |= POSE_IKSPLINE;
-}
-
-/* Tag which bones are members of Spline IK chains */
-static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
-{
- bPoseChannel *pchan;
-
- /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->constflag & PCHAN_HAS_SPLINEIK)
- splineik_init_tree_from_pchan(scene, ob, pchan);
- }
-}
-
-/* ----------- */
-
-/* Evaluate spline IK for a given bone */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
- int index, float ctime)
-{
- bSplineIKConstraint *ikData = tree->ikData;
- float poseHead[3], poseTail[3], poseMat[4][4];
- float splineVec[3], scaleFac, radius = 1.0f;
-
- /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
-
- copy_v3_v3(poseHead, pchan->pose_head);
- copy_v3_v3(poseTail, pchan->pose_tail);
-
- /* step 1: determine the positions for the endpoints of the bone */
- {
- float vec[4], dir[3], rad;
- float tailBlendFac = 1.0f;
-
- /* determine if the bone should still be affected by SplineIK */
- if (tree->points[index + 1] >= 1.0f) {
- /* spline doesn't affect the bone anymore, so done... */
- pchan->flag |= POSE_DONE;
- return;
- }
- else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
- /* blending factor depends on the amount of the bone still left on the chain */
- tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
- }
-
- /* tail endpoint */
- if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* convert the position to pose-space, then store it */
- mul_m4_v3(ob->imat, vec);
- interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
-
- /* set the new radius */
- radius = rad;
- }
-
- /* head endpoint */
- if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* store the position, and convert it to pose space */
- mul_m4_v3(ob->imat, vec);
- copy_v3_v3(poseHead, vec);
-
- /* set the new radius (it should be the average value) */
- radius = (radius + rad) / 2;
- }
- }
-
- /* step 2: determine the implied transform from these endpoints
- * - splineVec: the vector direction that the spline applies on the bone
- * - scaleFac: the factor that the bone length is scaled by to get the desired amount
- */
- sub_v3_v3v3(splineVec, poseTail, poseHead);
- scaleFac = len_v3(splineVec) / pchan->bone->length;
-
- /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
- * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
- */
- {
- float dmat[3][3], rmat[3][3], tmat[3][3];
- float raxis[3], rangle;
-
- /* compute the raw rotation matrix from the bone's current matrix by extracting only the
- * orientation-relevant axes, and normalizing them
- */
- copy_v3_v3(rmat[0], pchan->pose_mat[0]);
- copy_v3_v3(rmat[1], pchan->pose_mat[1]);
- copy_v3_v3(rmat[2], pchan->pose_mat[2]);
- normalize_m3(rmat);
-
- /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
- normalize_v3(splineVec);
-
- /* calculate smallest axis-angle rotation necessary for getting from the
- * current orientation of the bone, to the spline-imposed direction
- */
- cross_v3_v3v3(raxis, rmat[1], splineVec);
-
- rangle = dot_v3v3(rmat[1], splineVec);
- CLAMP(rangle, -1.0f, 1.0f);
- rangle = acosf(rangle);
-
- /* multiply the magnitude of the angle by the influence of the constraint to
- * control the influence of the SplineIK effect
- */
- rangle *= tree->con->enforce;
-
- /* construct rotation matrix from the axis-angle rotation found above
- * - this call takes care to make sure that the axis provided is a unit vector first
- */
- axis_angle_to_mat3(dmat, raxis, rangle);
-
- /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
- * while still maintaining roll control from the existing bone animation
- */
- mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
- normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
- copy_m4_m3(poseMat, tmat);
- }
-
- /* step 4: set the scaling factors for the axes */
- {
- /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
- mul_v3_fl(poseMat[1], scaleFac);
-
- /* set the scaling factors of the x and z axes from... */
- switch (ikData->xzScaleMode) {
- case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
- {
- /* original scales get used */
- float scale;
-
- /* x-axis scale */
- scale = len_v3(pchan->pose_mat[0]);
- mul_v3_fl(poseMat[0], scale);
- /* z-axis scale */
- scale = len_v3(pchan->pose_mat[2]);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_INVERSE:
- {
- /* old 'volume preservation' method using the inverse scale */
- float scale;
-
- /* calculate volume preservation factor which is
- * basically the inverse of the y-scaling factor
- */
- if (fabsf(scaleFac) != 0.0f) {
- scale = 1.0f / fabsf(scaleFac);
-
- /* we need to clamp this within sensible values */
- /* NOTE: these should be fine for now, but should get sanitised in future */
- CLAMP(scale, 0.0001f, 100000.0f);
- }
- else
- scale = 1.0f;
-
- /* apply the scaling */
- mul_v3_fl(poseMat[0], scale);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
- {
- /* improved volume preservation based on the Stretch To constraint */
- float final_scale;
-
- /* as the basis for volume preservation, we use the inverse scale factor... */
- if (fabsf(scaleFac) != 0.0f) {
- /* NOTE: The method here is taken wholesale from the Stretch To constraint */
- float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
-
- if (bulge > 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
- float bulge_max = max_ff(ikData->bulge_max, 1.0f);
- float hard = min_ff(bulge, bulge_max);
-
- float range = bulge_max - 1.0f;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
- if (bulge < 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
- float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
- float hard = max_ff(bulge, bulge_min);
-
- float range = 1.0f - bulge_min;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
-
- /* compute scale factor for xz axes from this value */
- final_scale = sqrt(bulge);
- }
- else {
- /* no scaling, so scale factor is simple */
- final_scale = 1.0f;
- }
-
- /* apply the scaling (assuming normalised scale) */
- mul_v3_fl(poseMat[0], final_scale);
- mul_v3_fl(poseMat[2], final_scale);
- break;
- }
- }
-
- /* finally, multiply the x and z scaling by the radius of the curve too,
- * to allow automatic scales to get tweaked still
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
- mul_v3_fl(poseMat[0], radius);
- mul_v3_fl(poseMat[2], radius);
- }
- }
-
- /* step 5: set the location of the bone in the matrix */
- if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
- /* when the 'no-root' option is affected, the chain can retain
- * the shape but be moved elsewhere
- */
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else if (tree->con->enforce < 1.0f) {
- /* when the influence is too low
- * - blend the positions for the 'root' bone
- * - stick to the parent for any other
- */
- if (pchan->parent) {
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else {
- /* FIXME: this introduces popping artifacts when we reach 0.0 */
- interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
- }
- }
- copy_v3_v3(poseMat[3], poseHead);
-
- /* finally, store the new transform */
- copy_m4_m4(pchan->pose_mat, poseMat);
- copy_v3_v3(pchan->pose_head, poseHead);
-
- /* recalculate tail, as it's now outdated after the head gets adjusted above! */
- BKE_pose_where_is_bone_tail(pchan);
-
- /* done! */
- pchan->flag |= POSE_DONE;
-}
-
-/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
-{
- tSplineIK_Tree *tree;
-
- /* for each pose-tree, execute it if it is spline, otherwise just free it */
- while ((tree = pchan_root->siktree.first) != NULL) {
- int i;
-
- /* walk over each bone in the chain, calculating the effects of spline IK
- * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
- * so that dependencies are correct
- */
- for (i = tree->chainlen - 1; i >= 0; i--) {
- bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
- }
-
- /* free the tree info specific to SplineIK trees now */
- if (tree->chain)
- MEM_freeN(tree->chain);
- if (tree->free_points)
- MEM_freeN(tree->points);
-
- /* free this tree */
- BLI_freelinkN(&pchan_root->siktree, tree);
- }
-}
-
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
@@ -2623,7 +2138,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
* - this is not integrated as an IK plugin, since it should be able
* to function in conjunction with standard IK
*/
- splineik_init_tree(scene, ob, ctime);
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
/* 3. the main loop, channels are already hierarchical sorted from root to children */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -2633,7 +2148,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
@@ -2703,3 +2218,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob)
return ob->bb;
}
+
+/************** Graph evaluation ********************/
+
+bPoseChannel *BKE_armature_ik_solver_find_root(
+ bPoseChannel *pchan,
+ bKinematicConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ /* Exclude tip from chain. */
+ rootchan = rootchan->parent;
+ }
+ if (rootchan != NULL) {
+ int segcount = 0;
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->rootbone) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ }
+ return rootchan;
+}
+
+bPoseChannel *BKE_armature_splineik_solver_find_root(
+ bPoseChannel *pchan,
+ bSplineIKConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ int segcount = 0;
+ BLI_assert(rootchan != NULL);
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->chainlen) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ return rootchan;
+}
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
new file mode 100644
index 00000000000..ceda9f056bb
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -0,0 +1,697 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Defines and code for core node types
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_fcurve.h"
+#include "BKE_scene.h"
+
+#include "BIK_api.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+/* ********************** SPLINE IK SOLVER ******************* */
+
+/* Temporary evaluation tree data used for Spline IK */
+typedef struct tSplineIK_Tree {
+ struct tSplineIK_Tree *next, *prev;
+
+ int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
+
+ bool free_points; /* free the point positions array */
+ short chainlen; /* number of bones in the chain */
+
+ float *points; /* parametric positions for the joints along the curve */
+ bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
+
+ bPoseChannel *root; /* bone that is the root node of the chain */
+
+ bConstraint *con; /* constraint for this chain */
+ bSplineIKConstraint *ikData; /* constraint settings for this chain */
+} tSplineIK_Tree;
+
+/* ----------- */
+
+/* Tag the bones in the chain formed by the given bone for IK */
+static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
+{
+ bPoseChannel *pchan, *pchanRoot = NULL;
+ bPoseChannel *pchanChain[255];
+ bConstraint *con = NULL;
+ bSplineIKConstraint *ikData = NULL;
+ float boneLengths[255], *jointPoints;
+ float totLength = 0.0f;
+ bool free_joints = 0;
+ int segcount = 0;
+
+ /* find the SplineIK constraint */
+ for (con = pchan_tip->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ ikData = con->data;
+
+ /* target can only be curve */
+ if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
+ continue;
+ /* skip if disabled */
+ if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
+ continue;
+
+ /* otherwise, constraint is ok... */
+ break;
+ }
+ }
+ if (con == NULL)
+ return;
+
+ /* make sure that the constraint targets are ok
+ * - this is a workaround for a depsgraph bug...
+ */
+ if (ikData->tar) {
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ /* only happens on reload file, but violates depsgraph still... fix! */
+ if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ BKE_displist_make_curveTypes(scene, ikData->tar, 0);
+
+ /* path building may fail in EditMode after removing verts [#33268]*/
+ if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ /* BLI_assert(cu->path != NULL); */
+ return;
+ }
+ }
+ }
+
+ /* find the root bone and the chain of bones from the root to the tip
+ * NOTE: this assumes that the bones are connected, but that may not be true... */
+ for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
+ /* store this segment in the chain */
+ pchanChain[segcount] = pchan;
+
+ /* if performing rebinding, calculate the length of the bone */
+ boneLengths[segcount] = pchan->bone->length;
+ totLength += boneLengths[segcount];
+ }
+
+ if (segcount == 0)
+ return;
+ else
+ pchanRoot = pchanChain[segcount - 1];
+
+ /* perform binding step if required */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
+ float segmentLen = (1.0f / (float)segcount);
+ int i;
+
+ /* setup new empty array for the points list */
+ if (ikData->points)
+ MEM_freeN(ikData->points);
+ ikData->numpoints = ikData->chainlen + 1;
+ ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
+
+ /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
+ ikData->points[0] = 1.0f;
+
+ /* perform binding of the joints to parametric positions along the curve based
+ * proportion of the total length that each bone occupies
+ */
+ for (i = 0; i < segcount; i++) {
+ /* 'head' joints, traveling towards the root of the chain
+ * - 2 methods; the one chosen depends on whether we've got usable lengths
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
+ /* 1) equi-spaced joints */
+ ikData->points[i + 1] = ikData->points[i] - segmentLen;
+ }
+ else {
+ /* 2) to find this point on the curve, we take a step from the previous joint
+ * a distance given by the proportion that this bone takes
+ */
+ ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
+ }
+ }
+
+ /* spline has now been bound */
+ ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
+ }
+
+ /* disallow negative values (happens with float precision) */
+ CLAMP_MIN(ikData->points[segcount], 0.0f);
+
+ /* apply corrections for sensitivity to scaling on a copy of the bind points,
+ * since it's easier to determine the positions of all the joints beforehand this way
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
+ float splineLen, maxScale;
+ int i;
+
+ /* make a copy of the points array, that we'll store in the tree
+ * - although we could just multiply the points on the fly, this approach means that
+ * we can introduce per-segment stretchiness later if it is necessary
+ */
+ jointPoints = MEM_dupallocN(ikData->points);
+ free_joints = 1;
+
+ /* get the current length of the curve */
+ /* NOTE: this is assumed to be correct even after the curve was resized */
+ splineLen = ikData->tar->curve_cache->path->totdist;
+
+ /* calculate the scale factor to multiply all the path values by so that the
+ * bone chain retains its current length, such that
+ * maxScale * splineLen = totLength
+ */
+ maxScale = totLength / splineLen;
+
+ /* apply scaling correction to all of the temporary points */
+ /* TODO: this is really not adequate enough on really short chains */
+ for (i = 0; i < segcount; i++)
+ jointPoints[i] *= maxScale;
+ }
+ else {
+ /* just use the existing points array */
+ jointPoints = ikData->points;
+ free_joints = 0;
+ }
+
+ /* make a new Spline-IK chain, and store it in the IK chains */
+ /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
+ {
+ /* make new tree */
+ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
+ tree->type = CONSTRAINT_TYPE_SPLINEIK;
+
+ tree->chainlen = segcount;
+
+ /* copy over the array of links to bones in the chain (from tip to root) */
+ tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
+ memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
+
+ /* store reference to joint position array */
+ tree->points = jointPoints;
+ tree->free_points = free_joints;
+
+ /* store references to different parts of the chain */
+ tree->root = pchanRoot;
+ tree->con = con;
+ tree->ikData = ikData;
+
+ /* AND! link the tree to the root */
+ BLI_addtail(&pchanRoot->siktree, tree);
+ }
+
+ /* mark root channel having an IK tree */
+ pchanRoot->flag |= POSE_IKSPLINE;
+}
+
+/* Tag which bones are members of Spline IK chains */
+static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
+{
+ bPoseChannel *pchan;
+
+ /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->constflag & PCHAN_HAS_SPLINEIK)
+ splineik_init_tree_from_pchan(scene, ob, pchan);
+ }
+}
+
+/* ----------- */
+
+/* Evaluate spline IK for a given bone */
+static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
+ int index, float ctime)
+{
+ bSplineIKConstraint *ikData = tree->ikData;
+ float poseHead[3], poseTail[3], poseMat[4][4];
+ float splineVec[3], scaleFac, radius = 1.0f;
+
+ /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+
+ copy_v3_v3(poseHead, pchan->pose_head);
+ copy_v3_v3(poseTail, pchan->pose_tail);
+
+ /* step 1: determine the positions for the endpoints of the bone */
+ {
+ float vec[4], dir[3], rad;
+ float tailBlendFac = 1.0f;
+
+ /* determine if the bone should still be affected by SplineIK */
+ if (tree->points[index + 1] >= 1.0f) {
+ /* spline doesn't affect the bone anymore, so done... */
+ pchan->flag |= POSE_DONE;
+ return;
+ }
+ else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
+ /* blending factor depends on the amount of the bone still left on the chain */
+ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
+ }
+
+ /* tail endpoint */
+ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* convert the position to pose-space, then store it */
+ mul_m4_v3(ob->imat, vec);
+ interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
+
+ /* set the new radius */
+ radius = rad;
+ }
+
+ /* head endpoint */
+ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* store the position, and convert it to pose space */
+ mul_m4_v3(ob->imat, vec);
+ copy_v3_v3(poseHead, vec);
+
+ /* set the new radius (it should be the average value) */
+ radius = (radius + rad) / 2;
+ }
+ }
+
+ /* step 2: determine the implied transform from these endpoints
+ * - splineVec: the vector direction that the spline applies on the bone
+ * - scaleFac: the factor that the bone length is scaled by to get the desired amount
+ */
+ sub_v3_v3v3(splineVec, poseTail, poseHead);
+ scaleFac = len_v3(splineVec) / pchan->bone->length;
+
+ /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
+ * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
+ */
+ {
+ float dmat[3][3], rmat[3][3], tmat[3][3];
+ float raxis[3], rangle;
+
+ /* compute the raw rotation matrix from the bone's current matrix by extracting only the
+ * orientation-relevant axes, and normalizing them
+ */
+ copy_v3_v3(rmat[0], pchan->pose_mat[0]);
+ copy_v3_v3(rmat[1], pchan->pose_mat[1]);
+ copy_v3_v3(rmat[2], pchan->pose_mat[2]);
+ normalize_m3(rmat);
+
+ /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
+ normalize_v3(splineVec);
+
+ /* calculate smallest axis-angle rotation necessary for getting from the
+ * current orientation of the bone, to the spline-imposed direction
+ */
+ cross_v3_v3v3(raxis, rmat[1], splineVec);
+
+ rangle = dot_v3v3(rmat[1], splineVec);
+ CLAMP(rangle, -1.0f, 1.0f);
+ rangle = acosf(rangle);
+
+ /* multiply the magnitude of the angle by the influence of the constraint to
+ * control the influence of the SplineIK effect
+ */
+ rangle *= tree->con->enforce;
+
+ /* construct rotation matrix from the axis-angle rotation found above
+ * - this call takes care to make sure that the axis provided is a unit vector first
+ */
+ axis_angle_to_mat3(dmat, raxis, rangle);
+
+ /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
+ * while still maintaining roll control from the existing bone animation
+ */
+ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
+ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
+ copy_m4_m3(poseMat, tmat);
+ }
+
+ /* step 4: set the scaling factors for the axes */
+ {
+ /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
+ mul_v3_fl(poseMat[1], scaleFac);
+
+ /* set the scaling factors of the x and z axes from... */
+ switch (ikData->xzScaleMode) {
+ case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
+ {
+ /* original scales get used */
+ float scale;
+
+ /* x-axis scale */
+ scale = len_v3(pchan->pose_mat[0]);
+ mul_v3_fl(poseMat[0], scale);
+ /* z-axis scale */
+ scale = len_v3(pchan->pose_mat[2]);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_INVERSE:
+ {
+ /* old 'volume preservation' method using the inverse scale */
+ float scale;
+
+ /* calculate volume preservation factor which is
+ * basically the inverse of the y-scaling factor
+ */
+ if (fabsf(scaleFac) != 0.0f) {
+ scale = 1.0f / fabsf(scaleFac);
+
+ /* we need to clamp this within sensible values */
+ /* NOTE: these should be fine for now, but should get sanitised in future */
+ CLAMP(scale, 0.0001f, 100000.0f);
+ }
+ else
+ scale = 1.0f;
+
+ /* apply the scaling */
+ mul_v3_fl(poseMat[0], scale);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
+ {
+ /* improved volume preservation based on the Stretch To constraint */
+ float final_scale;
+
+ /* as the basis for volume preservation, we use the inverse scale factor... */
+ if (fabsf(scaleFac) != 0.0f) {
+ /* NOTE: The method here is taken wholesale from the Stretch To constraint */
+ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
+
+ if (bulge > 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
+ float bulge_max = max_ff(ikData->bulge_max, 1.0f);
+ float hard = min_ff(bulge, bulge_max);
+
+ float range = bulge_max - 1.0f;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
+ float hard = max_ff(bulge, bulge_min);
+
+ float range = 1.0f - bulge_min;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+
+ /* compute scale factor for xz axes from this value */
+ final_scale = sqrtf(bulge);
+ }
+ else {
+ /* no scaling, so scale factor is simple */
+ final_scale = 1.0f;
+ }
+
+ /* apply the scaling (assuming normalised scale) */
+ mul_v3_fl(poseMat[0], final_scale);
+ mul_v3_fl(poseMat[2], final_scale);
+ break;
+ }
+ }
+
+ /* finally, multiply the x and z scaling by the radius of the curve too,
+ * to allow automatic scales to get tweaked still
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
+ mul_v3_fl(poseMat[0], radius);
+ mul_v3_fl(poseMat[2], radius);
+ }
+ }
+
+ /* step 5: set the location of the bone in the matrix */
+ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
+ /* when the 'no-root' option is affected, the chain can retain
+ * the shape but be moved elsewhere
+ */
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else if (tree->con->enforce < 1.0f) {
+ /* when the influence is too low
+ * - blend the positions for the 'root' bone
+ * - stick to the parent for any other
+ */
+ if (pchan->parent) {
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else {
+ /* FIXME: this introduces popping artifacts when we reach 0.0 */
+ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
+ }
+ }
+ copy_v3_v3(poseMat[3], poseHead);
+
+ /* finally, store the new transform */
+ copy_m4_m4(pchan->pose_mat, poseMat);
+ copy_v3_v3(pchan->pose_head, poseHead);
+
+ /* recalculate tail, as it's now outdated after the head gets adjusted above! */
+ BKE_pose_where_is_bone_tail(pchan);
+
+ /* done! */
+ pchan->flag |= POSE_DONE;
+}
+
+/* Evaluate the chain starting from the nominated bone */
+static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ tSplineIK_Tree *tree;
+
+ /* for each pose-tree, execute it if it is spline, otherwise just free it */
+ while ((tree = pchan_root->siktree.first) != NULL) {
+ int i;
+
+ /* walk over each bone in the chain, calculating the effects of spline IK
+ * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
+ * so that dependencies are correct
+ */
+ for (i = tree->chainlen - 1; i >= 0; i--) {
+ bPoseChannel *pchan = tree->chain[i];
+ splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ }
+
+ /* free the tree info specific to SplineIK trees now */
+ if (tree->chain)
+ MEM_freeN(tree->chain);
+ if (tree->free_points)
+ MEM_freeN(tree->points);
+
+ /* free this tree */
+ BLI_freelinkN(&pchan_root->siktree, tree);
+ }
+}
+
+void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
+{
+ splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ splineik_execute_tree(scene, ob, pchan_root, ctime);
+}
+
+/* *************** Depsgraph evaluation callbacks ************ */
+
+void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+ Scene *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);
+
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* We demand having proper pose. */
+ BLI_assert(ob->pose != NULL);
+ BLI_assert((ob->pose->flag & POSE_RECALC) == 0);
+
+ /* imat is needed for solvers. */
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ /* 1. clear flags */
+ for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ }
+
+ /* 2a. construct the IK tree (standard IK) */
+ BIK_initialize_tree(scene, ob, ctime);
+
+ /* 2b. construct the Spline IK trees
+ * - this is not integrated as an IK plugin, since it should be able
+ * to function in conjunction with standard IK
+ */
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ bArmature *arm = (bArmature *)ob->data;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ BLI_assert(ob->type == OB_ARMATURE);
+ if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
+ Bone *bone = pchan->bone;
+ if (bone) {
+ copy_m4_m4(pchan->pose_mat, bone->arm_mat);
+ copy_v3_v3(pchan->pose_head, bone->arm_head);
+ copy_v3_v3(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ else {
+ /* TODO(sergey): Currently if there are constraints full transform is being
+ * evaluated in BKE_pose_constraints_evaluate.
+ */
+ if (pchan->constraints.first == NULL) {
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* pass */
+ }
+ else {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+ }
+ }
+}
+
+void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ Scene *scene = G.main->scene.first;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* IK are being solved separately/ */
+ }
+ else {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+}
+
+void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+ bPoseChannel *pchan)
+{
+ float imat[4][4];
+ DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name);
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
+ }
+}
+
+void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BIK_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_eval_flush(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);
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* 6. release the IK tree */
+ BIK_release_tree(scene, ob, ctime);
+
+ ob->recalc &= ~OB_RECALC_ALL;
+}
+
+void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL);
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
+ printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
+ ob->id.name + 2, ob->proxy_from->id.name + 2);
+ }
+}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index b6ea780576e..37bd9c5db5c 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -263,7 +263,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* but use new Scene pointer */
curscene = bfd->curscene;
- track_undo_scene = (mode == LOAD_UNDO && curscreen && bfd->main->wm.first);
+ track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
if (curscene == NULL) curscene = bfd->main->scene.first;
/* empty file, we add a scene to make Blender work */
@@ -283,13 +283,17 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* clear_global will free G.main, here we can still restore pointers */
blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- curscene = curscreen->scene;
+ /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
+ if (curscreen) {
+ curscene = curscreen->scene;
+ }
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
curscreen->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen);
}
}
}
@@ -305,7 +309,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
CTX_data_main_set(C, G.main);
- sound_init_main(G.main);
+ BKE_sound_init_main(G.main);
if (bfd->user) {
@@ -619,7 +623,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports)
static void (*blender_test_break_cb)(void) = NULL;
-void set_blender_test_break_cb(void (*func)(void))
+void BKE_blender_callback_test_break_set(void (*func)(void))
{
blender_test_break_cb = func;
}
@@ -683,7 +687,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
}
/* name can be a dynamic string */
-void BKE_write_undo(bContext *C, const char *name)
+void BKE_undo_write(bContext *C, const char *name)
{
uintptr_t maxmem, totmem, memused;
int nr /*, success */ /* UNUSED */;
@@ -701,7 +705,7 @@ void BKE_write_undo(bContext *C, const char *name)
while (undobase.last != curundo) {
uel = undobase.last;
BLI_remlink(&undobase, uel);
- BLO_free_memfile(&uel->memfile);
+ BLO_memfile_free(&uel->memfile);
MEM_freeN(uel);
}
@@ -723,7 +727,7 @@ void BKE_write_undo(bContext *C, const char *name)
UndoElem *first = undobase.first;
BLI_remlink(&undobase, first);
/* the merge is because of compression */
- BLO_merge_memfile(&first->memfile, &first->next->memfile);
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
MEM_freeN(first);
}
}
@@ -778,7 +782,7 @@ void BKE_write_undo(bContext *C, const char *name)
UndoElem *first = undobase.first;
BLI_remlink(&undobase, first);
/* the merge is because of compression */
- BLO_merge_memfile(&first->memfile, &first->next->memfile);
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
MEM_freeN(first);
}
}
@@ -817,13 +821,13 @@ void BKE_undo_step(bContext *C, int step)
}
}
-void BKE_reset_undo(void)
+void BKE_undo_reset(void)
{
UndoElem *uel;
uel = undobase.first;
while (uel) {
- BLO_free_memfile(&uel->memfile);
+ BLO_memfile_free(&uel->memfile);
uel = uel->next;
}
@@ -850,7 +854,7 @@ void BKE_undo_name(bContext *C, const char *name)
}
/* name optional */
-int BKE_undo_valid(const char *name)
+bool BKE_undo_is_valid(const char *name)
{
if (name) {
UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
@@ -862,15 +866,16 @@ int BKE_undo_valid(const char *name)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *BKE_undo_get_name(int nr, int *active)
+const char *BKE_undo_get_name(int nr, bool *r_active)
{
UndoElem *uel = BLI_findlink(&undobase, nr);
- if (active) *active = 0;
+ if (r_active) *r_active = false;
if (uel) {
- if (active && uel == curundo)
- *active = 1;
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
@@ -936,15 +941,16 @@ bool BKE_undo_save_file(const char *filename)
}
/* sets curscene */
-Main *BKE_undo_get_main(Scene **scene)
+Main *BKE_undo_get_main(Scene **r_scene)
{
Main *mainp = NULL;
BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
if (bfd) {
mainp = bfd->main;
- if (scene)
- *scene = bfd->curscene;
+ if (r_scene) {
+ *r_scene = bfd->curscene;
+ }
MEM_freeN(bfd);
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 3488cff7315..76544e5ed42 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -80,6 +80,10 @@
#include "BKE_bpath.h" /* own include */
+#ifndef _MSC_VER
+# include "BLI_strict_flags.h"
+#endif
+
static bool checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
{
ReportList *reports = (ReportList *)userdata;
@@ -204,18 +208,19 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
* \returns found: 1/0.
*/
#define MAX_RECUR 16
-static int findFileRecursive(char *filename_new,
- const char *dirname,
- const char *filename,
- int *filesize,
- int *recur_depth)
+static bool missing_files_find__recursive(
+ char *filename_new,
+ const char *dirname,
+ const char *filename,
+ off_t *r_filesize,
+ int *r_recur_depth)
{
/* file searching stuff */
DIR *dir;
struct dirent *de;
BLI_stat_t status;
char path[FILE_MAX];
- int size;
+ off_t size;
bool found = false;
dir = opendir(dirname);
@@ -223,8 +228,8 @@ static int findFileRecursive(char *filename_new,
if (dir == NULL)
return found;
- if (*filesize == -1)
- *filesize = 0; /* dir opened fine */
+ if (*r_filesize == -1)
+ *r_filesize = 0; /* dir opened fine */
while ((de = readdir(dir)) != NULL) {
@@ -240,18 +245,18 @@ static int findFileRecursive(char *filename_new,
if (STREQLEN(filename, de->d_name, FILE_MAX)) { /* name matches */
/* open the file to read its size */
size = status.st_size;
- if ((size > 0) && (size > *filesize)) { /* find the biggest file */
- *filesize = size;
+ if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ *r_filesize = size;
BLI_strncpy(filename_new, path, FILE_MAX);
found = true;
}
}
}
else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*recur_depth <= MAX_RECUR) {
- (*recur_depth)++;
- found |= findFileRecursive(filename_new, path, filename, filesize, recur_depth);
- (*recur_depth)--;
+ if (*r_recur_depth <= MAX_RECUR) {
+ (*r_recur_depth)++;
+ found |= missing_files_find__recursive(filename_new, path, filename, r_filesize, r_recur_depth);
+ (*r_recur_depth)--;
}
}
}
@@ -266,14 +271,14 @@ typedef struct BPathFind_Data {
bool find_all;
} BPathFind_Data;
-static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
{
BPathFind_Data *data = (BPathFind_Data *)userdata;
char filename_new[FILE_MAX];
- int filesize = -1;
+ off_t filesize = -1;
int recur_depth = 0;
- int found;
+ bool found;
if (data->find_all == false) {
if (BLI_exists(path_src)) {
@@ -283,9 +288,10 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char
filename_new[0] = '\0';
- found = findFileRecursive(filename_new,
- data->searchdir, BLI_path_basename(path_src),
- &filesize, &recur_depth);
+ found = missing_files_find__recursive(
+ filename_new,
+ data->searchdir, BLI_path_basename(path_src),
+ &filesize, &recur_depth);
if (filesize == -1) { /* could not open dir */
BKE_reportf(data->reports, RPT_WARNING,
@@ -316,13 +322,14 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis
const bool find_all)
{
struct BPathFind_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
data.basedir = bmain->name;
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, findMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, (void *)&data);
+ BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
}
/* Run a visitor on a string, replacing the contents of the string as needed. */
@@ -364,6 +371,9 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+
if (absbase) {
BLI_path_abs(path_src, absbase);
}
@@ -393,7 +403,7 @@ static bool rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *a
}
if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN((*path));
+ MEM_freeN(*path);
(*path) = BLI_strdup(path_dst);
return true;
}
@@ -423,12 +433,17 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
Image *ima;
ima = (Image *)id;
- if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
- if (!ima->packedfile) {
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
- BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* image may have been painted onto (and not saved, T44543) */
+ !BKE_image_is_dirty(ima))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ }
}
}
}
@@ -589,12 +604,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
/* might want an option not to loop over all strips */
- int len = MEM_allocN_len(se) / sizeof(*se);
- int i;
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
/* only operate on one path */
- len = MIN2(1, len);
+ len = MIN2(1u, len);
}
for (i = 0; i < len; i++, se++) {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 10d77921515..2464b3b2668 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -103,8 +103,8 @@ static void brush_defaults(Brush *brush)
brush->jitter = 0.0f;
/* BRUSH TEXTURE SETTINGS */
- default_mtex(&brush->mtex);
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
brush->texture_sample_bias = 0; /* value to added to texture samples */
brush->texture_overlay_alpha = 33;
@@ -469,7 +469,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1);
if (idtest == NULL) { /* new tex */
if (id) idtest = (ID *)BKE_texture_copy((Tex *)id);
- else idtest = (ID *)add_texture(G.main, "Tex");
+ else idtest = (ID *)BKE_texture_add(G.main, "Tex");
idtest->us--;
}
if (idtest != id) {
@@ -782,13 +782,13 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
* inconsistency. */
-float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush)
+const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb;
}
-float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush)
+const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
@@ -819,7 +819,7 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
brush->size = size;
}
-int BKE_brush_size_get(const Scene *scene, Brush *brush)
+int BKE_brush_size_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
@@ -827,7 +827,7 @@ int BKE_brush_size_get(const Scene *scene, Brush *brush)
return (int)((float)size * U.pixelsize);
}
-int BKE_brush_use_locked_size(const Scene *scene, Brush *brush)
+int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -836,7 +836,7 @@ int BKE_brush_use_locked_size(const Scene *scene, Brush *brush)
(brush->flag & BRUSH_LOCK_SIZE);
}
-int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush)
+int BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -845,7 +845,7 @@ int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush)
(brush->flag & BRUSH_SIZE_PRESSURE);
}
-int BKE_brush_use_alpha_pressure(const Scene *scene, Brush *brush)
+int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -864,7 +864,7 @@ void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojec
brush->unprojected_radius = unprojected_radius;
}
-float BKE_brush_unprojected_radius_get(const Scene *scene, Brush *brush)
+float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -883,14 +883,14 @@ void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha)
brush->alpha = alpha;
}
-float BKE_brush_alpha_get(const Scene *scene, Brush *brush)
+float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_ALPHA) ? ups->alpha : brush->alpha;
}
-float BKE_brush_weight_get(const Scene *scene, Brush *brush)
+float BKE_brush_weight_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -920,9 +920,10 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
}
/* scale brush size to reflect a change in the brush's unprojected radius */
-void BKE_brush_scale_size(int *r_brush_size,
- float new_unprojected_radius,
- float old_unprojected_radius)
+void BKE_brush_scale_size(
+ int *r_brush_size,
+ float new_unprojected_radius,
+ float old_unprojected_radius)
{
float scale = new_unprojected_radius;
/* avoid division by zero */
@@ -970,7 +971,7 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
-/* Uses the brush curve control to find a strength value between 0 and 1 */
+/* Uses the brush curve control to find a strength value */
float BKE_brush_curve_strength(Brush *br, float p, const float len)
{
float strength;
@@ -980,6 +981,15 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len)
strength = curvemapping_evaluateF(br->curve, 0, p);
+ return strength;
+}
+
+
+/* Uses the brush curve control to find a strength value between 0 and 1 */
+float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
+{
+ float strength = BKE_brush_curve_strength(br, p, len);
+
CLAMP(strength, 0.0f, 1.0f);
return strength;
@@ -1041,7 +1051,7 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
for (i = 0; i < side; ++i) {
for (j = 0; j < side; ++j) {
float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength(br, magn, half);
+ im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
}
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 451656a9bca..87d81a9e921 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -30,16 +30,19 @@
*/
#include <stdlib.h>
+#include <stddef.h>
#include "DNA_camera_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_ID.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_camera.h"
@@ -47,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "GPU_compositing.h"
@@ -71,6 +75,10 @@ void *BKE_camera_add(Main *bmain, const char *name)
GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
+ /* stereoscopy 3d */
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.f * 0.065f;
+
return cam;
}
@@ -138,7 +146,7 @@ void BKE_camera_make_local(Camera *cam)
void BKE_camera_free(Camera *ca)
{
- BKE_free_animdata((ID *)ca);
+ BKE_animdata_free((ID *)ca);
}
/******************************** Camera Usage *******************************/
@@ -213,7 +221,7 @@ void BKE_camera_params_init(CameraParams *params)
params->clipend = 100.0f;
}
-void BKE_camera_params_from_object(CameraParams *params, Object *ob)
+void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
{
if (!ob)
return;
@@ -255,7 +263,7 @@ void BKE_camera_params_from_object(CameraParams *params, Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -274,7 +282,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView
params->shiftx *= params->zoom;
params->shifty *= params->zoom;
- params->zoom = 1.0f / params->zoom;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params->zoom;
}
else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */
@@ -283,13 +291,13 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView
params->clipsta = -params->clipend;
params->is_ortho = true;
- /* make sure any changes to this match ED_view3d_radius_to_ortho_dist() */
+ /* make sure any changes to this match ED_view3d_radius_to_dist_ortho() */
params->ortho_scale = rv3d->dist * sensor_size / v3d->lens;
- params->zoom = 2.0f;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
}
else {
/* perspective view */
- params->zoom = 2.0f;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
}
}
@@ -384,8 +392,10 @@ void BKE_camera_params_compute_matrix(CameraParams *params)
/***************************** Camera View Frame *****************************/
-void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const bool do_clip, const float scale[3],
- float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
+void BKE_camera_view_frame_ex(
+ const Scene *scene, const Camera *camera,
+ const float drawsize, const bool do_clip, const float scale[3],
+ float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
{
float facx, facy;
float depth;
@@ -456,7 +466,7 @@ void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, cons
r_vec[3][0] = r_shift[0] - facx; r_vec[3][1] = r_shift[1] + facy; r_vec[3][2] = depth;
}
-void BKE_camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3])
+void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec[4][3])
{
float dummy_asp[2];
float dummy_shift[2];
@@ -502,7 +512,9 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data)
data->tot++;
}
-static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *params, CameraViewFrameData *data)
+static void camera_frame_fit_data_init(
+ const Scene *scene, const Object *ob,
+ CameraParams *params, CameraViewFrameData *data)
{
float camera_rotmat_transposed_inversed[4][4];
unsigned int i;
@@ -521,7 +533,7 @@ static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *p
BKE_camera_params_compute_matrix(params);
/* initialize callback data */
- copy_m3_m4(data->camera_rotmat, ob->obmat);
+ copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat);
normalize_m3(data->camera_rotmat);
/* To transform a plane which is in its homogeneous representation (4d vector),
* we need the inverse of the transpose of the transform matrix... */
@@ -672,7 +684,8 @@ bool BKE_camera_view_frame_fit_to_scene(
}
bool BKE_camera_view_frame_fit_to_coords(
- Scene *scene, float (*cos)[3], int num_cos, Object *camera_ob, float r_co[3], float *r_scale)
+ const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob,
+ float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -690,6 +703,255 @@ bool BKE_camera_view_frame_fit_to_coords(
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
+/******************* multiview matrix functions ***********************/
+
+static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+{
+ copy_m4_m4(r_modelmat, camera->obmat);
+}
+
+static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+{
+ Camera *data = (Camera *)camera->data;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ float sizemat[4][4];
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ camera_model_matrix(camera, r_modelmat);
+ return;
+ }
+ else {
+ float size[3];
+ mat4_to_size(size, camera->obmat);
+ size_to_mat4(sizemat, size);
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* rotation */
+ if (convergence_mode == CAM_S3D_TOE) {
+ float angle;
+ float angle_sin, angle_cos;
+ float toeinmat[4][4];
+ float rotmat[4][4];
+
+ unit_m4(rotmat);
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ fac = -fac;
+ fac_signed = -fac_signed;
+ }
+
+ angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
+
+ angle_cos = cosf(angle * fac_signed);
+ angle_sin = sinf(angle * fac_signed);
+
+ rotmat[0][0] = angle_cos;
+ rotmat[2][0] = -angle_sin;
+ rotmat[0][2] = angle_sin;
+ rotmat[2][2] = angle_cos;
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ /* set the rotation */
+ copy_m4_m4(toeinmat, rotmat);
+ /* set the translation */
+ toeinmat[3][0] = interocular_distance * fac_signed;
+
+ /* transform */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
+ /* rotate perpendicular to the interocular line */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* translate along the interocular line */
+ unit_m4(toeinmat);
+ toeinmat[3][0] = -interocular_distance * fac_signed;
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* rotate to toe-in angle */
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ }
+ else {
+ normalize_m4_m4(r_modelmat, camera->obmat);
+
+ /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
+ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+}
+
+/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
+void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+{
+ BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
+ invert_m4(r_viewmat);
+}
+
+/* left is the default */
+static bool camera_is_left(const char *viewname)
+{
+ if (viewname && viewname[0] != '\0') {
+ return !STREQ(viewname, STEREO_RIGHT_NAME);
+ }
+ return true;
+}
+
+void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ const bool is_left = camera_is_left(viewname);
+ camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
+ }
+ normalize_m4(r_modelmat);
+}
+
+static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
+{
+ SceneRenderView *srv;
+ char name[MAX_NAME];
+ const char *camera_name = camera->id.name + 2;
+ const int len_name = strlen(camera_name);
+
+ name[0] = '\0';
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ const int len_suffix = strlen(srv->suffix);
+
+ if (len_name < len_suffix)
+ continue;
+
+ if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
+ BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
+ break;
+ }
+ }
+
+ if (name[0] != '\0') {
+ Base *base = BKE_scene_base_find_by_name(scene, name);
+ if (base) {
+ return base->object;
+ }
+ }
+
+ return camera;
+}
+
+/* returns the camera to be used for render */
+Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return camera;
+ }
+ else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ return camera;
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
+ return camera_multiview_advanced(scene, camera, suffix);
+ }
+}
+
+static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+{
+ Camera *data = camera->data;
+ float shift = data->shiftx;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ bool is_left = true;
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ if (viewname && viewname[0]) {
+ is_left = STREQ(viewname, STEREO_LEFT_NAME);
+ }
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ return shift;
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* Note: in viewport, parallel renders as offaxis, but in render it does parallel */
+ if (ELEM(convergence_mode, CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL)) {
+ shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed;
+ }
+
+ return shift;
+}
+
+float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+ Camera *data = camera->data;
+
+ BLI_assert(camera->type == OB_CAMERA);
+
+ if (!is_multiview) {
+ return data->shiftx;
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ return data->shiftx;
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ return camera_stereo3d_shift_x(camera, viewname);
+ }
+}
+
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+{
+ if (camera->type == OB_CAMERA) {
+ params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
+ }
+}
+
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
if (camera->type == OB_CAMERA) {
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index a2c78822aab..649778c71f5 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -392,12 +392,7 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
{
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MEdge *medge = cddm->medge;
- int i;
- int prevstart = 0;
- int prevdraw = 1;
- bool draw = true;
-
+ GPUDrawObject *gdo;
if (cddm->pbvh && cddm->pbvh_draw &&
BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH)
{
@@ -407,58 +402,36 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg
}
GPU_edge_setup(dm);
- for (i = 0; i < dm->numEdgeData; i++, medge++) {
- if ((drawAllEdges || (medge->flag & ME_EDGEDRAW)) &&
- (drawLooseEdges || !(medge->flag & ME_LOOSEEDGE)))
- {
- draw = true;
+ gdo = dm->drawObject;
+ if (gdo->edges && gdo->points) {
+ if (drawAllEdges && drawLooseEdges) {
+ GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2);
}
- else {
- draw = false;
+ else if (drawAllEdges) {
+ GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
}
- if (prevdraw != draw) {
- if (prevdraw > 0 && (i - prevstart) > 0) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
- }
- prevstart = i;
+ else {
+ GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
+ GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2);
}
- prevdraw = draw;
- }
- if (prevdraw > 0 && (i - prevstart) > 0) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
}
GPU_buffer_unbind();
}
static void cdDM_drawLooseEdges(DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MEdge *medge = cddm->medge;
- int i;
-
- int prevstart = 0;
- int prevdraw = 1;
- int draw = 1;
-
+ int start;
+ int count;
+
GPU_edge_setup(dm);
- for (i = 0; i < dm->numEdgeData; i++, medge++) {
- if (medge->flag & ME_LOOSEEDGE) {
- draw = 1;
- }
- else {
- draw = 0;
- }
- if (prevdraw != draw) {
- if (prevdraw > 0 && (i - prevstart) > 0) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
- }
- prevstart = i;
- }
- prevdraw = draw;
- }
- if (prevdraw > 0 && (i - prevstart) > 0) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, prevstart * 2, (i - prevstart) * 2);
+
+ start = (dm->drawObject->loose_edge_offset * 2);
+ count = (dm->drawObject->totedge - dm->drawObject->loose_edge_offset) * 2;
+
+ if (count) {
+ GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
}
+
GPU_buffer_unbind();
}
@@ -470,7 +443,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
int a;
if (cddm->pbvh && cddm->pbvh_draw) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
@@ -527,7 +500,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
* (the same as it'll display without UV maps in textured view)
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
GPU_set_tpage(NULL, false, false);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -786,14 +759,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
if (tottri == 0) {
/* avoid buffer problems in following code */
}
- if (setDrawOptions == NULL) {
+ else if (setDrawOptions == NULL) {
/* just draw the entire face array */
glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3);
}
else {
/* we need to check if the next material changes */
int next_actualFace = dm->drawObject->triangle_to_mface[0];
- int prev_mat_nr = -1;
+ short prev_mat_nr = -1;
for (i = 0; i < tottri; i++) {
//int actualFace = dm->drawObject->triangle_to_mface[i];
@@ -912,7 +885,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
* works fine for matcap
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
setMaterial(1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -1246,7 +1219,7 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
* works fine for matcap
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
setMaterial(userData, 1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -2545,16 +2518,16 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
if (LIKELY(v1 != v2)) {
- void **eh_p = BLI_edgehash_lookup_p(ehash, v1, v2);
+ void **val_p;
- if (eh_p) {
- newe[i] = GET_INT_FROM_POINTER(*eh_p);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = GET_INT_FROM_POINTER(*val_p);
}
else {
STACK_PUSH(olde, i);
STACK_PUSH(medge, *med);
newe[i] = c;
- BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
+ *val_p = SET_INT_IN_POINTER(c);
c++;
}
}
@@ -2569,7 +2542,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
/* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
PolyKey *mpgh;
poly_keys = MEM_mallocN(sizeof(PolyKey) * totpoly, __func__);
- poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly, false);
+ poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
/* Duplicates allowed because our compare function is not pure equality */
BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 3b3fe323f2b..e3ff96853b3 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -997,19 +997,19 @@ int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int
return 0;
}
-static void cloth_free_edgelist(LinkNode **edgelist, unsigned int numverts)
+static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int numverts)
{
if (edgelist) {
unsigned int i;
for (i = 0; i < numverts; i++) {
- BLI_linklist_free(edgelist[i], NULL);
+ BLI_linklist_free(edgelist[i].list, NULL);
}
MEM_freeN(edgelist);
}
}
-static void cloth_free_errorsprings(Cloth *cloth, LinkNode **edgelist)
+static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
{
if ( cloth->springs != NULL ) {
LinkNode *search = cloth->springs;
@@ -1260,7 +1260,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
MEdge *medge = dm->getEdgeArray (dm);
MFace *mface = dm->getTessFaceArray (dm);
int index2 = 0; // our second vertex index
- LinkNode **edgelist = NULL;
+ LinkNodePair *edgelist;
EdgeSet *edgeset = NULL;
LinkNode *search = NULL, *search2 = NULL;
@@ -1276,7 +1276,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
cloth->springs = NULL;
cloth->edgeset = NULL;
- edgelist = MEM_callocN ( sizeof (LinkNode *) * numverts, "cloth_edgelist_alloc" );
+ edgelist = MEM_callocN(sizeof(*edgelist) * numverts, "cloth_edgelist_alloc" );
if (!edgelist)
return 0;
@@ -1347,8 +1347,9 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->type = CLOTH_SPRING_TYPE_SHEAR;
spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
- BLI_linklist_append ( &edgelist[spring->ij], spring );
- BLI_linklist_append ( &edgelist[spring->kl], spring );
+ BLI_linklist_append(&edgelist[spring->ij], spring);
+ BLI_linklist_append(&edgelist[spring->kl], spring);
+
shear_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1371,8 +1372,9 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->type = CLOTH_SPRING_TYPE_SHEAR;
spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
- BLI_linklist_append ( &edgelist[spring->ij], spring );
- BLI_linklist_append ( &edgelist[spring->kl], spring );
+ BLI_linklist_append(&edgelist[spring->ij], spring);
+ BLI_linklist_append(&edgelist[spring->kl], spring);
+
shear_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1389,7 +1391,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
break;
tspring2 = search2->link;
- search = edgelist[tspring2->kl];
+ search = edgelist[tspring2->kl].list;
while ( search ) {
tspring = search->link;
index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 89c3e4b0cfc..3c70bd4eeb5 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_threads.h"
#include "BKE_colortools.h"
#include "BKE_curve.h"
@@ -52,6 +53,10 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#ifdef _OPENMP
+# include <omp.h>
+#endif
+
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -790,7 +795,17 @@ float curvemap_evaluateF(const CurveMap *cuma, float value)
float curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
const CurveMap *cuma = cumap->cm + cur;
- return curvemap_evaluateF(cuma, value);
+ float val = curvemap_evaluateF(cuma, value);
+
+ /* account for clipping */
+ if (cumap->flag & CUMA_DO_CLIP) {
+ if (val < cumap->curr.ymin)
+ val = cumap->curr.ymin;
+ else if (val > cumap->curr.ymax)
+ val = cumap->curr.ymax;
+ }
+
+ return val;
}
/* vector case */
@@ -994,7 +1009,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
copy_v3_v3(rgb, fp);
IMB_colormanagement_processor_apply_v3(cm_processor, rgb);
- hist->data_luma[i] = rgb_to_luma(rgb);
+ hist->data_luma[i] = IMB_colormanagement_get_luminance(rgb);
hist->data_r[i] = rgb[0];
hist->data_g[i] = rgb[1];
hist->data_b[i] = rgb[2];
@@ -1002,7 +1017,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
else if (ibuf->rect) {
cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
- hist->data_luma[i] = (float)rgb_to_luma_byte(cp) / 255.0f;
+ hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
hist->data_r[i] = (float)cp[0] / 255.0f;
hist->data_g[i] = (float)cp[1] / 255.0f;
hist->data_b[i] = (float)cp[2] / 255.0f;
@@ -1019,18 +1034,28 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
- int x, y, c;
+#ifdef _OPENMP
+ const int num_threads = BLI_system_thread_count();
+#endif
+ int a, y;
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
- const float *rf = NULL;
- unsigned char *rc = NULL;
- unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
- int savedlines, saveline;
- float rgba[4], ycc[3], luma;
+ unsigned char *display_buffer;
+ unsigned int bin_lum[256] = {0},
+ bin_r[256] = {0},
+ bin_g[256] = {0},
+ bin_b[256] = {0},
+ bin_a[256] = {0};
+ unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}},
+ bin_r_t[BLENDER_MAX_THREADS][256] = {{0}},
+ bin_g_t[BLENDER_MAX_THREADS][256] = {{0}},
+ bin_b_t[BLENDER_MAX_THREADS][256] = {{0}},
+ bin_a_t[BLENDER_MAX_THREADS][256] = {{0}};
int ycc_mode = -1;
const bool is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
+ int rows_per_sample_line;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1060,24 +1085,18 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
break;
}
- /* temp table to count pix value for histogram */
- bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
- bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
- bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
- bin_a = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
- bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
-
/* convert to number of lines with logarithmic scale */
scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y;
+ CLAMP_MIN(scopes->sample_lines, 1);
if (scopes->sample_full)
scopes->sample_lines = ibuf->y;
/* scan the image */
- savedlines = 0;
- for (c = 0; c < 3; c++) {
- scopes->minmax[c][0] = 25500.0f;
- scopes->minmax[c][1] = -25500.0f;
+ rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ for (a = 0; a < 3; a++) {
+ scopes->minmax[a][0] = 25500.0f;
+ scopes->minmax[a][1] = -25500.0f;
}
scopes->waveform_tot = ibuf->x * scopes->sample_lines;
@@ -1096,24 +1115,38 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3");
scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel");
- if (is_float)
- rf = ibuf->rect_float;
+ if (ibuf->rect_float) {
+ cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+ }
else {
- rc = (unsigned char *)IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
+ display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf,
+ view_settings,
+ display_settings,
+ &cache_handle);
}
-
- if (ibuf->rect_float)
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+ /* Keep number of threads in sync with the merge parts below. */
+#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if(ibuf->y > 256)
for (y = 0; y < ibuf->y; y++) {
- if (savedlines < scopes->sample_lines && y >= ((savedlines) * ibuf->y) / (scopes->sample_lines + 1)) {
- saveline = 1;
- }
+#ifdef _OPENMP
+ const int thread_idx = omp_get_thread_num();
+#else
+ const int thread_idx = 0;
+#endif
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
+ float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX},
+ max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ int x, c;
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
else {
- saveline = 0;
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
}
for (x = 0; x < ibuf->x; x++) {
-
+ float rgba[4], ycc[3], luma;
if (is_float) {
copy_v4_v4(rgba, rf);
IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
@@ -1124,32 +1157,32 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
}
/* we still need luma for histogram */
- luma = rgb_to_luma(rgba);
+ luma = IMB_colormanagement_get_luminance(rgba);
/* check for min max */
if (ycc_mode == -1) {
for (c = 0; c < 3; c++) {
- if (rgba[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgba[c];
- if (rgba[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgba[c];
+ if (rgba[c] < min[c]) min[c] = rgba[c];
+ if (rgba[c] > max[c]) max[c] = rgba[c];
}
}
else {
rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
for (c = 0; c < 3; c++) {
ycc[c] *= INV_255;
- if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c];
- if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c];
+ if (ycc[c] < min[c]) min[c] = ycc[c];
+ if (ycc[c] > max[c]) max[c] = ycc[c];
}
}
/* increment count for histo*/
- bin_lum[get_bin_float(luma)] += 1;
- bin_r[get_bin_float(rgba[0])] += 1;
- bin_g[get_bin_float(rgba[1])] += 1;
- bin_b[get_bin_float(rgba[2])] += 1;
- bin_a[get_bin_float(rgba[3])] += 1;
+ bin_lum_t[thread_idx][get_bin_float(luma)] += 1;
+ bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1;
+ bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1;
+ bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1;
+ bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1;
/* save sample if needed */
- if (saveline) {
+ if (do_sample_line) {
const float fx = (float)x / (float)ibuf->x;
const int idx = 2 * (ibuf->x * savedlines + x);
save_sample_line(scopes, idx, fx, rgba, ycc);
@@ -1158,29 +1191,57 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
rf += ibuf->channels;
rc += ibuf->channels;
}
- if (saveline)
- savedlines += 1;
+#pragma omp critical
+ {
+ for (c = 0; c < 3; c++) {
+ if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c];
+ if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c];
+ }
+ }
+ }
+
+#ifdef _OPENMP
+ if (ibuf->y > 256) {
+ for (a = 0; a < num_threads; a++) {
+ int b;
+ for (b = 0; b < 256; b++) {
+ bin_lum[b] += bin_lum_t[a][b];
+ bin_r[b] += bin_r_t[a][b];
+ bin_g[b] += bin_g_t[a][b];
+ bin_b[b] += bin_b_t[a][b];
+ bin_a[b] += bin_a_t[a][b];
+ }
+ }
+ }
+ else
+#endif
+ {
+ memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum));
+ memcpy(bin_r, bin_r_t[0], sizeof(bin_r));
+ memcpy(bin_g, bin_g_t[0], sizeof(bin_g));
+ memcpy(bin_b, bin_b_t[0], sizeof(bin_b));
+ memcpy(bin_a, bin_a_t[0], sizeof(bin_a));
}
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
- for (x = 0; x < 256; x++) {
- bin_lum[x] = sqrt (bin_lum[x]);
- bin_r[x] = sqrt(bin_r[x]);
- bin_g[x] = sqrt(bin_g[x]);
- bin_b[x] = sqrt(bin_b[x]);
- bin_a[x] = sqrt(bin_a[x]);
+ for (a = 0; a < 256; a++) {
+ bin_lum[a] = sqrt (bin_lum[a]);
+ bin_r[a] = sqrt(bin_r[a]);
+ bin_g[a] = sqrt(bin_g[a]);
+ bin_b[a] = sqrt(bin_b[a]);
+ bin_a[a] = sqrt(bin_a[a]);
}
#endif
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
- for (x = 0; x < 256; x++) {
- if (bin_lum[x] > nl) nl = bin_lum[x];
- if (bin_r[x] > nr) nr = bin_r[x];
- if (bin_g[x] > ng) ng = bin_g[x];
- if (bin_b[x] > nb) nb = bin_b[x];
- if (bin_a[x] > na) na = bin_a[x];
+ for (a = 0; a < 256; a++) {
+ if (bin_lum[a] > nl) nl = bin_lum[a];
+ if (bin_r[a] > nr) nr = bin_r[a];
+ if (bin_g[a] > ng) ng = bin_g[a];
+ if (bin_b[a] > nb) nb = bin_b[a];
+ if (bin_a[a] > na) na = bin_a[a];
}
divl = nl ? 1.0 / (double)nl : 1.0;
diva = na ? 1.0 / (double)na : 1.0;
@@ -1188,18 +1249,13 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
divg = ng ? 1.0 / (double)ng : 1.0;
divb = nb ? 1.0 / (double)nb : 1.0;
- for (x = 0; x < 256; x++) {
- scopes->hist.data_luma[x] = bin_lum[x] * divl;
- scopes->hist.data_r[x] = bin_r[x] * divr;
- scopes->hist.data_g[x] = bin_g[x] * divg;
- scopes->hist.data_b[x] = bin_b[x] * divb;
- scopes->hist.data_a[x] = bin_a[x] * diva;
+ for (a = 0; a < 256; a++) {
+ scopes->hist.data_luma[a] = bin_lum[a] * divl;
+ scopes->hist.data_r[a] = bin_r[a] * divr;
+ scopes->hist.data_g[a] = bin_g[a] * divg;
+ scopes->hist.data_b[a] = bin_b[a] * divb;
+ scopes->hist.data_a[a] = bin_a[a] * diva;
}
- MEM_freeN(bin_lum);
- MEM_freeN(bin_r);
- MEM_freeN(bin_g);
- MEM_freeN(bin_b);
- MEM_freeN(bin_a);
if (cm_processor)
IMB_colormanagement_processor_free(cm_processor);
@@ -1303,3 +1359,9 @@ void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *
{
BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
}
+
+bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1,
+ const ColorManagedColorspaceSettings *settings2)
+{
+ return STREQ(settings1->name, settings2->name);
+}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index c38a1239f12..fa8ab14de06 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -4318,7 +4318,7 @@ static void constraints_init_typeinfo(void)
/* This function should be used for getting the appropriate type-info when only
* a constraint type is known
*/
-bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
+const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
/* initialize the type-info list? */
if (CTI_INIT) {
@@ -4343,7 +4343,7 @@ bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(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.
*/
-bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
+const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
/* only return typeinfo for valid constraints */
if (con)
@@ -4373,7 +4373,7 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_re
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
/* perform any special freeing constraint may have */
@@ -4447,7 +4447,7 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
static bConstraint *add_new_constraint_internal(const char *name, short type)
{
bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint");
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
const char *newName;
/* Set up a generic constraint datablock */
@@ -4574,7 +4574,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
bConstraint *con;
for (con = conlist->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
if (cti->id_looper)
@@ -4609,7 +4609,7 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
BLI_duplicatelist(dst, src);
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* make a new copy of the constraint's data */
con->data = MEM_dupallocN(con->data);
@@ -4724,7 +4724,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
*/
void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintOb *cob;
bConstraintTarget *ct;
@@ -4791,7 +4791,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
/* Get the list of targets required for solving a constraint */
void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
@@ -4836,7 +4836,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
/* loop over available constraints, solving and blending them */
for (con = conlist->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
/* these we can skip completely (invalid constraints...) */
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 911bb19a594..392aac13999 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -266,7 +266,7 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em
* modifiers with on cage editing that are enabled and support computing
* deform matrices */
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, dm))
continue;
@@ -322,7 +322,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
@@ -343,7 +343,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
@@ -377,7 +377,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
Mesh *me = (Mesh *)ob->data;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index b6a167da53d..1a67ac76937 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -147,7 +147,7 @@ void BKE_curve_free(Curve *cu)
BKE_curve_editNurb_free(cu);
BKE_curve_unlink(cu);
- BKE_free_animdata((ID *)cu);
+ BKE_animdata_free((ID *)cu);
if (cu->mat)
MEM_freeN(cu->mat);
@@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
}
}
+/* forward differencing method for first derivative of cubic bezier curve */
+void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0, rt1, rt2, f;
+ int a;
+
+ f = 1.0f / (float)it;
+
+ rt0 = 3.0f * (q1 - q0);
+ rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
+ rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
+
+ q0 = rt0;
+ q1 = f * (rt1 + rt2);
+ q2 = 2.0f * f * rt1;
+
+ for (a = 0; a <= it; a++) {
+ *p = q0;
+ p = (float *)(((char *)p) + stride);
+ q0 += q1;
+ q1 += q2;
+ }
+}
+
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3],
float p[3], int it, int stride)
{
@@ -2522,7 +2546,8 @@ void BKE_curve_bevelList_free(ListBase *bev)
}
MEM_freeN(bl);
}
- bev->first = bev->last = NULL;
+
+ BLI_listbase_clear(bev);
}
void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
@@ -4344,8 +4369,10 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
}
else {
i = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; i--; bp++)
+ for (bp = nu->bp; i--; bp++) {
mul_m4_v3(mat, bp->vec);
+ bp->radius *= unit_scale;
+ }
}
}
@@ -4422,9 +4449,6 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr && nu->mat_nr >= index) {
nu->mat_nr--;
- if (curvetype == OB_CURVE) {
- nu->charidx--;
- }
}
}
}
@@ -4446,9 +4470,6 @@ void BKE_curve_material_index_clear(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
}
}
}
@@ -4475,9 +4496,6 @@ int BKE_curve_material_index_validate(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr > max_idx) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
is_valid = false;
}
}
@@ -4492,6 +4510,54 @@ int BKE_curve_material_index_validate(Curve *cu)
}
}
+void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
+{
+ const int curvetype = BKE_curve_type_get(cu);
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (curvetype == OB_FONT) {
+ struct CharInfo *strinfo;
+ int charinfo_len, i;
+
+ if (cu->editfont) {
+ EditFont *ef = cu->editfont;
+ strinfo = ef->textbufinfo;
+ charinfo_len = ef->len;
+ }
+ else {
+ strinfo = cu->strinfo;
+ charinfo_len = cu->len_wchar;
+ }
+
+ for (i = 0; i <= charinfo_len; i++) {
+ if (strinfo[i].mat_nr > 0) {
+ strinfo[i].mat_nr -= 1;
+ MAT_NR_REMAP(strinfo[i].mat_nr);
+ strinfo[i].mat_nr += 1;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ if (nurbs) {
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ MAT_NR_REMAP(nu->mat_nr);
+ }
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
{
r_rect->xmin = cu->xof + tb->x;
@@ -4500,3 +4566,27 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
r_rect->xmax = r_rect->xmin + tb->w;
r_rect->ymin = r_rect->ymax - tb->h;
}
+
+/* **** Depsgraph evaluation **** */
+
+void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Curve *curve)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, curve->id.name);
+ }
+ if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
+ 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 999f411cece..eced263d493 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1091,7 +1091,7 @@ static void layerDefault_mcol(void *data, int count)
static void layerDefault_origindex(void *data, int count)
{
- fill_vn_i((int *)data, count, ORIGINDEX_NONE);
+ copy_vn_i((int *)data, count, ORIGINDEX_NONE);
}
static void layerInterp_bweight(
@@ -1542,7 +1542,7 @@ static void CustomData_external_free(CustomData *data)
void CustomData_reset(CustomData *data)
{
memset(data, 0, sizeof(*data));
- fill_vn_i(data->typemap, CD_NUMTYPES, -1);
+ copy_vn_i(data->typemap, CD_NUMTYPES, -1);
}
void CustomData_free(CustomData *data, int totelem)
@@ -2294,7 +2294,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
}
}
- if (count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+ if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources);
}
void CustomData_swap(struct CustomData *data, int index, const int *corner_indices)
@@ -3852,7 +3852,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTra
if (tmp_data_src) {
if (UNLIKELY(sources_num > tmp_buff_size)) {
tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
}
for (j = 0; j < sources_num; j++) {
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 8f6d4385b55..da00aecf9c0 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1157,12 +1157,20 @@ bool BKE_object_data_transfer_dm(
const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
if (!geom_map_init[VDATA]) {
- if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != dm_src->getNumVerts(dm_src))) {
+ const int num_verts_src = dm_src->getNumVerts(dm_src);
+
+ if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of vertices, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ 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");
+ return changed;
+ }
+
BKE_mesh_remap_calc_verts_from_dm(
map_vert_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
@@ -1197,12 +1205,20 @@ bool BKE_object_data_transfer_dm(
const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
if (!geom_map_init[EDATA]) {
- if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != dm_src->getNumEdges(dm_src))) {
+ const int num_edges_src = dm_src->getNumEdges(dm_src);
+
+ if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of edges, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ 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");
+ return changed;
+ }
+
BKE_mesh_remap_calc_edges_from_dm(
map_edge_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
@@ -1248,12 +1264,20 @@ bool BKE_object_data_transfer_dm(
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
if (!geom_map_init[LDATA]) {
- if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != dm_src->getNumLoops(dm_src))) {
+ const int num_loops_src = dm_src->getNumLoops(dm_src);
+
+ if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of face corners, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ 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");
+ return changed;
+ }
+
BKE_mesh_remap_calc_loops_from_dm(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
@@ -1298,12 +1322,20 @@ bool BKE_object_data_transfer_dm(
CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
if (!geom_map_init[PDATA]) {
- if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != dm_src->getNumPolys(dm_src))) {
+ const int num_polys_src = dm_src->getNumPolys(dm_src);
+
+ if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of faces, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ 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");
+ return changed;
+ }
+
BKE_mesh_remap_calc_polys_from_dm(
map_poly_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, loops_dst, num_loops_dst,
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index dec27d2a056..501b749b464 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -31,6 +31,8 @@
#ifndef __DATA_TRANSFER_INTERN_H__
#define __DATA_TRANSFER_INTERN_H__
+#include "BKE_customdata.h" /* For cd_datatransfer_interp */
+
struct CustomDataTransferLayerMap;
struct CustomData;
struct ListBase;
@@ -38,11 +40,6 @@ struct ListBase;
float data_transfer_interp_float_do(
const int mix_mode, const float val_dst, const float val_src, const float mix_factor);
-/* Copied from BKE_customdata.h :( */
-typedef void (*cd_datatransfer_interp)(
- const struct CustomDataTransferLayerMap *laymap, void *dest,
- const void **sources, const float *weights, const int count, const float mix_factor);
-
void data_transfer_layersmapping_add_item(
struct ListBase *r_map, const int data_type, const int mix_mode,
const float mix_factor, const float *mix_weights,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 0adea59c245..88885da474b 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -649,7 +649,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
BLI_strncpy(prefix, name, sizeof(prefix));
/* first case; separator . - _ with extensions r R l L */
- if (is_char_sep(name[len - 2])) {
+ if ((len > 1) && is_char_sep(name[len - 2])) {
is_set = true;
switch (name[len - 1]) {
case 'l':
@@ -982,7 +982,7 @@ void BKE_defvert_extract_vgroup_to_vertweights(
}
}
else {
- fill_vn_fl(r_weights, invert_vgroup ? 1.0f : 0.0f, num_verts);
+ copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
}
}
@@ -1008,7 +1008,7 @@ void BKE_defvert_extract_vgroup_to_edgeweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_edges);
+ copy_vn_fl(r_weights, num_edges, 0.0f);
}
}
@@ -1031,7 +1031,7 @@ void BKE_defvert_extract_vgroup_to_loopweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_loops);
+ copy_vn_fl(r_weights, num_loops, 0.0f);
}
}
@@ -1060,7 +1060,7 @@ void BKE_defvert_extract_vgroup_to_polyweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_polys);
+ copy_vn_fl(r_weights, num_polys, 0.0f);
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 0451c2239ac..2fd53045e29 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -88,16 +88,25 @@
#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+
static SpinLock threaded_update_lock;
void DAG_init(void)
{
BLI_spin_init(&threaded_update_lock);
+ DEG_register_node_types();
}
void DAG_exit(void)
{
BLI_spin_end(&threaded_update_lock);
+ DEG_free_node_types();
}
/* Queue and stack operations for dag traversal
@@ -512,7 +521,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -574,7 +583,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node);
}
@@ -823,7 +832,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
/* object constraints */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -960,6 +969,10 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
/* also flush custom data mask */
((Object *)node->ob)->customdata_mask = node->customdata_mask;
+
+ if (node->parent == NULL) {
+ dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ }
}
}
/* now set relations equal, so that when only one parent changes, the correct recalcs are found */
@@ -1325,8 +1338,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU
void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated))
{
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
+ if (DEG_depsgraph_use_legacy()) {
+ EditorsUpdateIDCb = id_func;
+ EditorsUpdateSceneCb = scene_func;
+ }
+ else {
+ /* New dependency graph. */
+ DEG_editors_set_update_cb(id_func, scene_func);
+ }
}
static void dag_editors_id_update(Main *bmain, ID *id)
@@ -1525,7 +1544,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
Base *base;
BLI_listbase_clear(&tempbase);
-
+
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
dag_check_cycle(sce->theDag);
@@ -1617,32 +1636,65 @@ static void dag_scene_build(Main *bmain, Scene *sce)
/* clear all dependency graphs */
void DAG_relations_tag_update(Main *bmain)
{
- Scene *sce;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next)
- dag_scene_free(sce);
+ if (DEG_depsgraph_use_legacy()) {
+ Scene *sce;
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ dag_scene_free(sce);
+ }
+ }
+ else {
+ /* New dependency graph. */
+ DEG_relations_tag_update(bmain);
+ }
}
/* rebuild dependency graph only for a given scene */
void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
{
- dag_scene_free(sce);
- DAG_scene_relations_update(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ dag_scene_free(sce);
+ DAG_scene_relations_update(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_rebuild(bmain, sce);
+ }
}
/* create dependency graph if it was cleared or didn't exist yet */
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
- if (!sce->theDag)
- dag_scene_build(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ if (!sce->theDag)
+ dag_scene_build(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_update(bmain, sce);
+ }
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *sce)
+{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_debug_scene_relations_validate(bmain, sce);
+ }
}
void DAG_scene_free(Scene *sce)
{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
+ if (DEG_depsgraph_use_legacy()) {
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+ }
+ else {
+ if (sce->depsgraph) {
+ DEG_graph_free(sce->depsgraph);
+ sce->depsgraph = NULL;
+ }
}
}
@@ -1885,7 +1937,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
DagAdjList *itA;
Object *ob;
int lasttime;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ return;
+ }
+
if (sce->theDag == NULL) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
@@ -2011,7 +2067,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
if (ob->constraints.first) {
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -2296,7 +2352,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
}
}
-static void dag_group_on_visible_update(Group *group)
+static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
@@ -2318,7 +2374,7 @@ static void dag_group_on_visible_update(Group *group)
}
if (go->ob->dup_group)
- dag_group_on_visible_update(go->ob->dup_group);
+ dag_group_on_visible_update(scene, go->ob->dup_group);
}
}
@@ -2326,7 +2382,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
{
ListBase listbase;
DagSceneLayer *dsl;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ /* Inform new dependnecy graphs about visibility changes. */
+ DEG_on_visible_update(bmain, do_time);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2353,7 +2415,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ /* TODO(sergey): Why do we need armature here now but didn't need before? */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@@ -2371,7 +2434,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
lib_id_recalc_tag(bmain, &ob->id);
}
if (ob->dup_group)
- dag_group_on_visible_update(ob->dup_group);
+ dag_group_on_visible_update(scene, ob->dup_group);
}
}
@@ -2532,7 +2595,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
for (obt = bmain->object.first; obt; obt = obt->id.next) {
bConstraint *con;
for (con = obt->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
CONSTRAINT_TYPE_OBJECTSOLVER))
{
@@ -2605,7 +2668,12 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool do_flush = false;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_flush_tagged(bmain);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2649,6 +2717,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
int a;
bool updated = false;
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_check_recalc(bmain, scene, time);
+ return;
+ }
+
/* loop over all ID types */
a = set_listbasepointers(bmain, lbarray);
@@ -2765,6 +2838,11 @@ void DAG_ids_clear_recalc(Main *bmain)
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_id_tag_update_ex(bmain, id, flag);
+ return;
+ }
+
if (id == NULL) return;
if (G.debug & G_DEBUG_DEPSGRAPH) {
@@ -2916,7 +2994,7 @@ void DAG_pose_sort(Object *ob)
addtoroot = 0;
}
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -3156,6 +3234,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
DagNode *node;
+ if (!DEG_depsgraph_use_legacy()) {
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+ }
+
if (scene->theDag == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
@@ -3194,3 +3276,286 @@ bool DAG_is_acyclic(Scene *scene)
{
return scene->theDag->is_acyclic;
}
+
+#else
+
+/* *********************************************************************
+ * Stubs to avoid linking issues and make sure legacy crap is not used *
+ * *********************************************************************
+ */
+
+DagNodeQueue *queue_create(int UNUSED(slots))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void queue_raz(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void queue_delete(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *dag_init(void)
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *build_dag(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ short UNUSED(mask))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void free_forest(DagForest *UNUSED(Dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void dag_add_relation(DagForest *UNUSED(forest),
+ DagNode *UNUSED(fob1),
+ DagNode *UNUSED(fob2),
+ short UNUSED(rel),
+ const char *UNUSED(name))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* debug test functions */
+
+void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_adj_list(DagForest *UNUSED(dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_flush_update(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ unsigned int UNUSED(lay),
+ const short UNUSED(time))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_update_flags(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ unsigned int UNUSED(lay),
+ const bool UNUSED(do_time),
+ const bool UNUSED(do_invisible_flush))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ******************* DAG FOR ARMATURE POSE ***************** */
+
+void DAG_pose_sort(Object *UNUSED(ob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ************************ DAG FOR THREADED UPDATE ********************* */
+
+void DAG_threaded_update_begin(Scene *UNUSED(scene),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+/* ************************ DAG querying ********************* */
+
+Object *DAG_get_node_object(void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return "INVALID";
+}
+
+bool DAG_is_acyclic(Scene *UNUSED(scene))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return false;
+}
+
+/* ************************************
+ * This functions are to be supported *
+ * ************************************
+ */
+
+void DAG_init(void)
+{
+ DEG_register_node_types();
+}
+
+void DAG_exit(void)
+{
+ DEG_free_node_types();
+}
+
+/* ************************ API *********************** */
+
+void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ DEG_editors_set_update_cb(id_func, scene_func);
+}
+
+/* Tag all relations for update. */
+void DAG_relations_tag_update(Main *bmain)
+{
+ DEG_relations_tag_update(bmain);
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_rebuild(bmain, scene);
+}
+
+/* Create dependency graph if it was cleared or didn't exist yet. */
+void DAG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *scene)
+{
+ DEG_debug_scene_relations_validate(bmain, scene);
+}
+
+void DAG_scene_free(Scene *scene)
+{
+ DEG_scene_graph_free(scene);
+}
+
+void DAG_on_visible_update(Main *bmain, const bool do_time)
+{
+ DEG_on_visible_update(bmain, do_time);
+}
+
+void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ DEG_ids_check_recalc(bmain, scene, time);
+}
+
+void DAG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ DEG_id_tag_update_ex(bmain, id, flag);
+}
+
+void DAG_id_type_tag(Main *bmain, short idtype)
+{
+ DEG_id_type_tag(bmain, idtype);
+}
+
+int DAG_id_type_tagged(Main *bmain, short idtype)
+{
+ return DEG_id_type_tagged(bmain, idtype);
+}
+
+void DAG_ids_clear_recalc(Main *bmain)
+{
+ DEG_ids_clear_recalc(bmain);
+}
+
+short DAG_get_eval_flags_for_object(Scene *scene, void *object)
+{
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+}
+
+void DAG_ids_flush_tagged(Main *bmain)
+{
+ DEG_ids_flush_tagged(bmain);
+}
+
+/* ************************ DAG DEBUGGING ********************* */
+
+void DAG_print_dependencies(Main *UNUSED(bmain),
+ Scene *scene,
+ Object *UNUSED(ob))
+{
+ DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dd92a82bed2..3213b59b92d 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -53,6 +53,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
#include "BKE_mball.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -516,7 +517,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj
dl = dl->next;
}
- /* XXX (obedit && obedit->actcol) ? (obedit->actcol-1) : 0)) { */
+ /* XXX (obedit && obedit->actcol) ? (obedit->actcol - 1) : 0)) { */
if (totvert && (tot = BLI_scanfill_calc_ex(&sf_ctx,
scanfill_flag,
normal_proj)))
@@ -763,7 +764,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
pretessellatePoint = NULL;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, required_mode))
continue;
@@ -832,7 +833,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
if (pretessellatePoint) {
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -933,7 +934,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
ModifierApplyFlag appf = app_flag;
md->scene = scene;
@@ -1164,7 +1165,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
orcodm = create_orco_dm(scene, ob);
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1434,9 +1435,8 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
return;
}
- if (ELEM(cu->bevfac1_mapping,
- CU_BEVFAC_MAP_SEGMENT,
- CU_BEVFAC_MAP_SPLINE))
+ if (ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
+ ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE))
{
for (i = 0; i < SEGMENTSU(nu); i++) {
total_length += bl->seglen[i];
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 762b24dfdf8..8dac578ac0a 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -527,7 +527,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent
/* also update constraint targets */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
@@ -579,7 +579,7 @@ static void scene_setSubframe(Scene *scene, float subframe)
scene->r.subframe = subframe;
}
-static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene)
+static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene)
{
Base *base = NULL;
GroupObject *go = NULL;
@@ -1447,7 +1447,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
MEM_freeN(temp_data);
}
-static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surface)
+static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
@@ -1595,7 +1595,7 @@ static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surf
}
/* clears surface data back to zero */
-void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface)
+void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
if (sData && sData->type_data) {
@@ -1620,7 +1620,7 @@ void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* completely (re)initializes surface (only for point cache types)*/
-bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface)
+bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
/* free existing data */
@@ -1647,7 +1647,7 @@ bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* make sure allocated surface size matches current requirements */
-static bool dynamicPaint_checkSurfaceData(Scene *scene, DynamicPaintSurface *surface)
+static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
{
if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
return dynamicPaint_resetSurface(scene, surface);
@@ -2964,15 +2964,16 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c
/**
* Mix color values to canvas point.
*
- * \param surface canvas surface
- * \param index surface point index
- * \param paintFlags paint object flags
- * \param paintColor,Alpha,Wetness to be mixed paint values
- * \param timescale value used to adjust time dependent
+ * \param surface: Canvas surface
+ * \param index: Surface point index
+ * \param paintFlags: paint object flags
+ * \param paintColor,paintAlpha,paintWetness: To be mixed paint values
+ * \param timescale: Value used to adjust time dependent
* operations when using substeps
*/
-static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+static void dynamicPaint_mixPaintColors(
+ DynamicPaintSurface *surface, int index, int paintFlags,
+ const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
@@ -4696,7 +4697,7 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
return ret;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, Scene *scene)
+static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
{
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
return 1;
@@ -4716,7 +4717,7 @@ static int surface_needsAccelerationData(DynamicPaintSurface *surface)
}
/* Prepare for surface step by creating PaintBakeNormal data */
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintAdjData *adj_data = sData->adj_data;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 082edb01efd..fbce501f57f 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -521,8 +521,6 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
GLenum poly_prev = GL_ZERO;
GLenum shade_prev = GL_ZERO;
- (void)setMaterial; /* UNUSED */
-
/* currently unused -- each original face is handled separately */
(void)compareDrawOptions;
@@ -539,6 +537,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
if (bmdm->vertexCos) {
+ short prev_mat_nr = -1;
+
/* add direct access */
const float (*vertexCos)[3] = bmdm->vertexCos;
const float (*vertexNos)[3];
@@ -569,8 +569,14 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
setDrawOptions(userData, BM_elem_index_get(efa)));
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
+
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
if (poly_prev != GL_ZERO) glEnd();
@@ -645,6 +651,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
}
else {
+ short prev_mat_nr = -1;
+
BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE);
for (i = 0; i < tottri; i++) {
@@ -661,8 +669,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
@@ -985,7 +997,7 @@ static void emDM_drawMappedFacesTex(DerivedMesh *dm,
* ... because the material may use layer names to select different UV's
* see: [#34378]
*/
-static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face)
+static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index)
{
BMVert *eve = loop->v;
int i;
@@ -1028,7 +1040,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col);
}
if (attribs->tottang) {
- int index = i * 4 + index_in_face;
+ int index = face_index * 4 + index_in_face;
const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero;
glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
}
@@ -1100,14 +1112,14 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1116,7 +1128,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1124,7 +1136,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1204,14 +1216,14 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1220,7 +1232,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1228,7 +1240,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1968,7 +1980,7 @@ static void statvis_calc_thickness(
BLI_assert(min <= max);
- fill_vn_fl(face_dists, em->bm->totface, max);
+ copy_vn_fl(face_dists, em->bm->totface, max);
if (use_jit) {
int j;
@@ -2223,7 +2235,7 @@ static void statvis_calc_sharp(
(void)vertexCos; /* TODO */
- fill_vn_fl(vert_angles, em->bm->totvert, -M_PI);
+ copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
/* first assign float values to verts */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
@@ -2253,7 +2265,7 @@ static void statvis_calc_sharp(
}
void BKE_editmesh_statvis_calc(BMEditMesh *em, DerivedMesh *dm,
- MeshStatVis *statvis)
+ const MeshStatVis *statvis)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 2247b91df1d..87a5c6f149f 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -246,3 +246,21 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
break;
}
}
+
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
+{
+ BMIter iter;
+ BMVert *eve;
+ float (*orco)[3];
+ int i;
+
+ orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(orco[i], eve->co);
+ }
+
+ *r_numVerts = em->bm->totvert;
+
+ return orco;
+}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 296a56ada5d..785561d8239 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -1176,7 +1176,7 @@ void BKE_sim_debug_data_clear_category(const char *category)
GHashIterator iter;
BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
while (!BLI_ghashIterator_done(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */
if (elem->category_hash == category_hash)
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 81321b9dbc2..6e58513e38e 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -46,6 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_easing.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -69,6 +70,10 @@
#define SMALL -1.0e-10
#define SELECT 1
+#ifdef WITH_PYTHON
+static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
+#endif
+
/* ************************** Data-Level Functions ************************* */
/* ---------------------- Freeing --------------------------- */
@@ -309,19 +314,23 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt, bAction **action, bool *r_driven)
+FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt,
+ bAction **action, bool *r_driven, bool *r_special)
{
- return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven);
+ return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
- AnimData **animdata, bAction **action, bool *r_driven)
+FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **animdata,
+ bAction **action, bool *r_driven, bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
if (animdata) *animdata = NULL;
*r_driven = false;
+ *r_special = false;
+
+ if (action) *action = NULL;
/* there must be some RNA-pointer + property combon */
if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) {
@@ -342,10 +351,15 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
path = RNA_path_from_ID_to_property(&tptr, prop);
}
+ // XXX: the logic here is duplicated with a function up above
if (path) {
/* animation takes priority over drivers */
- if (adt->action && adt->action->curves.first)
+ if (adt->action && adt->action->curves.first) {
fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
+
+ if (fcu && action)
+ *action = adt->action;
+ }
/* if not animated, check if driven */
if (!fcu && (adt->drivers.first)) {
@@ -375,6 +389,32 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
}
}
}
+
+ /* if we still haven't found anything, check whether it's a "special" property */
+ if ((fcu == NULL) && (adt && adt->nla_tracks.first)) {
+ NlaTrack *nlt;
+ const char *propname = RNA_property_identifier(prop);
+
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ NlaStrip *strip;
+
+ if (fcu)
+ break;
+
+ /* FIXME: need to do recursive search here for correctness,
+ * but this will do for most use cases (i.e. interactive editing),
+ * where nested strips can't be easily edited
+ */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ fcu = list_find_fcurve(&strip->fcurves, propname, rnaindex);
+
+ if (fcu) {
+ *r_special = true;
+ break;
+ }
+ }
+ }
+ }
}
MEM_SAFE_FREE(path);
}
@@ -1496,7 +1536,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
};
/* Get driver variable typeinfo */
-static DriverVarTypeInfo *get_dvar_typeinfo(int type)
+static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
{
/* check if valid type */
if ((type >= 0) && (type < MAX_DVAR_TYPES))
@@ -1540,7 +1580,7 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
- DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
+ const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
/* sanity check */
if (ELEM(NULL, dvar, dvti))
@@ -1664,7 +1704,7 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
/* Evaluate a Driver Variable to get a value that contributes to the final */
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
{
- DriverVarTypeInfo *dvti;
+ const DriverVarTypeInfo *dvti;
/* sanity check */
if (ELEM(NULL, driver, dvar))
@@ -1772,7 +1812,9 @@ static float evaluate_driver(ChannelDriver *driver, const float evaltime)
/* this evaluates the expression using Python, and returns its result:
* - on errors it reports, then returns 0.0f
*/
+ BLI_mutex_lock(&python_driver_lock);
driver->curval = BPY_driver_exec(driver, evaltime);
+ BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
(void)evaltime;
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index af0db5e1c47..396a260c3b8 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -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
*/
-FModifierTypeInfo *get_fmodifier_typeinfo(int type)
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
{
/* initialize the type-info list? */
if (FMI_INIT) {
@@ -1065,7 +1065,7 @@ 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.
*/
-FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
+const FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
if (fcm)
@@ -1079,7 +1079,7 @@ FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
FModifier *add_fmodifier(ListBase *modifiers, int type)
{
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
FModifier *fcm;
/* sanity checks */
@@ -1119,7 +1119,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type)
/* Make a copy of the specified F-Modifier */
FModifier *copy_fmodifier(FModifier *src)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
FModifier *dst;
/* sanity check */
@@ -1153,7 +1153,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src)
BLI_duplicatelist(dst, src);
for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* make a new copy of the F-Modifier's data */
fcm->data = MEM_dupallocN(fcm->data);
@@ -1167,7 +1167,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src)
/* Remove and free the given F-Modifier from the given stack */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* sanity check */
if (fcm == NULL)
@@ -1266,7 +1266,7 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
/* find the first mdifier fitting these criteria */
for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */
/* check if applicable ones are fullfilled */
@@ -1296,7 +1296,7 @@ FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers)
}
for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL) {
continue;
@@ -1410,7 +1410,7 @@ float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
* (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
*/
for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL)
continue;
@@ -1458,7 +1458,7 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
/* evaluate modifiers */
for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL)
continue;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index cc9ad63d451..f6c4263cff7 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -179,7 +179,7 @@ static FreestyleLineSet *alloc_lineset(void)
return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
}
-FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name)
+FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name)
{
int lineset_index = BLI_listbase_count(&config->linesets);
@@ -187,7 +187,7 @@ FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char
BLI_addtail(&config->linesets, (void *)lineset);
BKE_freestyle_lineset_set_active_index(config, lineset_index);
- lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
lineset->flags |= FREESTYLE_LINESET_ENABLED;
lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES | FREESTYLE_SEL_IMAGE_BORDER;
lineset->qi = FREESTYLE_QI_VISIBLE;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index dd2155505fb..38a84296ca6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -119,7 +119,7 @@ void BKE_gpencil_free(bGPdata *gpd)
/* free animation data */
if (gpd->adt) {
- BKE_free_animdata(&gpd->id);
+ BKE_animdata_free(&gpd->id);
gpd->adt = NULL;
}
}
@@ -129,11 +129,11 @@ void BKE_gpencil_free(bGPdata *gpd)
/* add a new gp-frame to the given layer */
bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
- bGPDframe *gpf, *gf;
+ bGPDframe *gpf = NULL, *gf = NULL;
short state = 0;
/* error checking (neg frame only if they are not allowed in Blender!) */
- if ((gpl == NULL) || ((U.flag & USER_NONEGFRAMES) && (cframe <= 0)))
+ if (gpl == NULL)
return NULL;
/* allocate memory for this frame */
@@ -160,8 +160,14 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
/* check whether frame was added successfully */
if (state == -1) {
+ printf("Error: Frame (%d) existed already for this layer. Using existing frame\n", cframe);
+
+ /* free the newly created one, and use the old one instead */
MEM_freeN(gpf);
- printf("Error: frame (%d) existed already for this layer\n", cframe);
+
+ /* return existing frame instead... */
+ BLI_assert(gf != NULL);
+ gpf = gf;
}
else if (state == 0) {
/* add to end then! */
@@ -388,8 +394,6 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
/* error checking */
if (gpl == NULL) return NULL;
- /* No reason to forbid negative frames when they are allowed in Blender! */
- if ((U.flag & USER_NONEGFRAMES) && cframe <= 0) cframe = 1;
/* check if there is already an active frame */
if (gpl->actframe) {
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 8bda957f187..daf39116d76 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
@@ -53,6 +54,10 @@
#include "GPU_extensions.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -61,6 +66,7 @@ static int gNextIconId = 1;
static int gFirstIconId = 1;
+static GHash *gCachedPreviews = NULL;
static void icon_free(void *val)
{
@@ -105,30 +111,50 @@ void BKE_icons_init(int first_dyn_id)
gFirstIconId = first_dyn_id;
if (!gIcons)
- gIcons = BLI_ghash_int_new("icons_init gh");
+ gIcons = BLI_ghash_int_new(__func__);
+
+ if (!gCachedPreviews) {
+ gCachedPreviews = BLI_ghash_str_new(__func__);
+ }
}
void BKE_icons_free(void)
{
- if (gIcons)
+ if (gIcons) {
BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
+ gIcons = NULL;
+ }
+
+ if (gCachedPreviews) {
+ BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
+ gCachedPreviews = NULL;
+ }
}
-PreviewImage *BKE_previewimg_create(void)
+static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
{
PreviewImage *prv_img = NULL;
int i;
- prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv");
+ prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+ memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
+
+ if (deferred_data_size) {
+ prv_img->use_deferred = true;
+ }
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv_img->changed[i] = 1;
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
+PreviewImage *BKE_previewimg_create(void)
+{
+ return previewimg_create_ex(0);
+}
+
void BKE_previewimg_freefunc(void *link)
{
PreviewImage *prv = (PreviewImage *)link;
@@ -138,7 +164,6 @@ void BKE_previewimg_freefunc(void *link)
for (i = 0; i < NUM_ICON_SIZES; ++i) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
- prv->rect[i] = NULL;
}
if (prv->gputexture[i])
GPU_texture_free(prv->gputexture[i]);
@@ -156,6 +181,26 @@ void BKE_previewimg_free(PreviewImage **prv)
}
}
+void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
+{
+ MEM_SAFE_FREE(prv->rect[size]);
+ if (prv->gputexture[size]) {
+ GPU_texture_free(prv->gputexture[size]);
+ }
+ prv->h[size] = prv->w[size] = 0;
+ prv->flag[size] |= PRV_CHANGED;
+ prv->flag[size] &= ~PRV_USER_EDITED;
+ prv->changed_timestamp[size] = 0;
+}
+
+void BKE_previewimg_clear(struct PreviewImage *prv)
+{
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ BKE_previewimg_clear_single(prv, i);
+ }
+}
+
PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
{
PreviewImage *prv_img = NULL;
@@ -167,79 +212,186 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
if (prv->rect[i]) {
prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
}
- else {
- prv_img->rect[i] = NULL;
- }
prv_img->gputexture[i] = NULL;
}
}
return prv_img;
}
-void BKE_previewimg_free_id(ID *id)
+PreviewImage **BKE_previewimg_id_get_p(ID *id)
{
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- BKE_previewimg_free(&mat->preview);
- }
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- BKE_previewimg_free(&tex->preview);
- }
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- BKE_previewimg_free(&wo->preview);
+ switch (GS(id->name)) {
+#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; }
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Lamp);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+#undef ID_PRV_CASE
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- BKE_previewimg_free(&la->preview);
- }
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- BKE_previewimg_free(&img->preview);
+
+ return NULL;
+}
+
+void BKE_previewimg_id_free(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ if (prv_p) {
+ BKE_previewimg_free(prv_p);
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- BKE_previewimg_free(&br->preview);
+}
+
+PreviewImage *BKE_previewimg_id_ensure(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+
+ if (prv_p) {
+ if (*prv_p == NULL) {
+ *prv_p = BKE_previewimg_create();
+ }
+ return *prv_p;
}
+
+ return NULL;
}
-PreviewImage *BKE_previewimg_get(ID *id)
+PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- PreviewImage *prv_img = NULL;
+ return BLI_ghash_lookup(gCachedPreviews, name);
+}
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- if (!mat->preview) mat->preview = BKE_previewimg_create();
- prv_img = mat->preview;
+/**
+ * Generate an empty PreviewImage, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_ensure(const char *name)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) {
+ *prv_p = BKE_previewimg_create();
}
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- if (!tex->preview) tex->preview = BKE_previewimg_create();
- prv_img = tex->preview;
+ prv = *prv_p;
+ BLI_assert(prv);
+
+ return prv;
+}
+
+/**
+ * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_thumbnail_read(
+ const char *name, const char *path, const int source, bool force_update)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
+
+ if (prv_p) {
+ prv = *prv_p;
+ BLI_assert(prv);
}
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- if (!wo->preview) wo->preview = BKE_previewimg_create();
- prv_img = wo->preview;
+
+ if (prv && force_update) {
+ const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
+ /* If same path, no need to re-allocate preview, just clear it up. */
+ BKE_previewimg_clear(prv);
+ }
+ else {
+ BKE_previewimg_free(&prv);
+ }
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- if (!la->preview) la->preview = BKE_previewimg_create();
- prv_img = la->preview;
+
+ if (!prv) {
+ /* We pack needed data for lazy loading (source type, in a single char, and path). */
+ const size_t deferred_data_size = strlen(path) + 2;
+ char *deferred_data;
+
+ prv = previewimg_create_ex(deferred_data_size);
+ deferred_data = PRV_DEFERRED_DATA(prv);
+ deferred_data[0] = source;
+ memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+ force_update = true;
}
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- if (!img->preview) img->preview = BKE_previewimg_create();
- prv_img = img->preview;
+
+ if (force_update) {
+ if (prv_p) {
+ *prv_p = prv;
+ }
+ else {
+ BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
+ }
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- if (!br->preview) br->preview = BKE_previewimg_create();
- prv_img = br->preview;
+
+ return prv;
+}
+
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ if (prv) {
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
}
+}
- return prv_img;
+/** Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails. */
+void BKE_previewimg_ensure(PreviewImage *prv, const int size)
+{
+ if (prv->use_deferred) {
+ const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
+ const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
+
+ if (do_icon || do_preview) {
+ ImBuf *thumb;
+ char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = prv_deferred_data[0];
+ char *path = &prv_deferred_data[1];
+ int icon_w, icon_h;
+
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
+
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ if (do_preview) {
+ prv->w[ICON_SIZE_PREVIEW] = thumb->x;
+ prv->h[ICON_SIZE_PREVIEW] = thumb->y;
+ prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ if (do_icon) {
+ if (thumb->x > thumb->y) {
+ icon_w = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_h = (thumb->y * icon_w) / thumb->x + 1;
+ }
+ else if (thumb->x < thumb->y) {
+ icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_w = (thumb->x * icon_h) / thumb->y + 1;
+ }
+ else {
+ icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ }
+
+ IMB_scaleImBuf(thumb, icon_w, icon_h);
+ prv->w[ICON_SIZE_ICON] = icon_w;
+ prv->h[ICON_SIZE_ICON] = icon_h;
+ prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ IMB_freeImBuf(thumb);
+ }
+ }
+ }
}
void BKE_icon_changed(int id)
@@ -251,20 +403,20 @@ void BKE_icon_changed(int id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
if (icon) {
- PreviewImage *prv = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
/* all previews changed */
if (prv) {
int i;
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv->changed[i] = 1;
+ prv->flag[i] |= PRV_CHANGED;
prv->changed_timestamp[i]++;
}
}
}
}
-int BKE_icon_getid(struct ID *id)
+int BKE_icon_id_ensure(struct ID *id)
{
Icon *new_icon = NULL;
@@ -277,11 +429,11 @@ int BKE_icon_getid(struct ID *id)
id->icon_id = get_next_free_id();
if (!id->icon_id) {
- printf("BKE_icon_getid: Internal error - not enough IDs\n");
+ printf("%s: Internal error - not enough IDs\n", __func__);
return 0;
}
- new_icon = MEM_callocN(sizeof(Icon), "texicon");
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj = id;
new_icon->type = GS(id->name);
@@ -295,6 +447,40 @@ int BKE_icon_getid(struct ID *id)
return id->icon_id;
}
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
+int BKE_icon_preview_ensure(PreviewImage *preview)
+{
+ Icon *new_icon = NULL;
+
+ if (!preview || G.background)
+ return 0;
+
+ if (preview->icon_id)
+ return preview->icon_id;
+
+ preview->icon_id = get_next_free_id();
+
+ if (!preview->icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
+
+ new_icon->obj = preview;
+ new_icon->type = 0; /* Special, tags as non-ID icon/preview. */
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
+
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon);
+
+ return preview->icon_id;
+}
+
Icon *BKE_icon_get(int icon_id)
{
Icon *icon = NULL;
@@ -302,7 +488,7 @@ Icon *BKE_icon_get(int icon_id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
if (!icon) {
- printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id);
+ printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
return NULL;
}
@@ -311,23 +497,42 @@ Icon *BKE_icon_get(int icon_id)
void BKE_icon_set(int icon_id, struct Icon *icon)
{
- Icon *old_icon = NULL;
+ void **val_p;
- old_icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
-
- if (old_icon) {
- printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id);
+ if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
+ printf("%s: Internal error, icon already set: %d\n", __func__, icon_id);
return;
}
- BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon);
+ *val_p = icon;
}
-void BKE_icon_delete(struct ID *id)
+void BKE_icon_id_delete(struct ID *id)
{
-
if (!id->icon_id) return; /* no icon defined for library object */
BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
id->icon_id = 0;
}
+
+/**
+ * Remove icon and free data.
+ */
+void BKE_icon_delete(int icon_id)
+{
+ Icon *icon;
+
+ if (!icon_id) return; /* no icon defined for library object */
+
+ icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
+
+ if (icon) {
+ if (icon->type) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ icon_free(icon);
+ }
+}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 1b7a03ec80e..091d8a6ea17 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -37,11 +37,15 @@
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_idcode.h"
typedef struct {
unsigned short code;
const char *name, *plural;
+
+ const char *i18n_context;
int flags;
#define IDTYPE_FLAGS_ISLINKABLE (1 << 0)
@@ -50,41 +54,41 @@ typedef struct {
/* plural need to match rna_main.c's MainCollectionDef */
/* WARNING! Keep it in sync with i18n contexts in BLF_translation.h */
static IDType idtypes[] = {
- { ID_AC, "Action", "actions", IDTYPE_FLAGS_ISLINKABLE },
- { ID_AR, "Armature", "armatures", IDTYPE_FLAGS_ISLINKABLE },
- { ID_BR, "Brush", "brushes", IDTYPE_FLAGS_ISLINKABLE },
- { ID_CA, "Camera", "cameras", IDTYPE_FLAGS_ISLINKABLE },
- { ID_CU, "Curve", "curves", IDTYPE_FLAGS_ISLINKABLE },
- { ID_GD, "GPencil", "grease_pencil", IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
- { ID_GR, "Group", "groups", IDTYPE_FLAGS_ISLINKABLE },
- { ID_ID, "ID", "ids", 0 }, /* plural is fake */
- { ID_IM, "Image", "images", IDTYPE_FLAGS_ISLINKABLE },
- { ID_IP, "Ipo", "ipos", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
- { ID_KE, "Key", "shape_keys", 0 },
- { ID_LA, "Lamp", "lamps", IDTYPE_FLAGS_ISLINKABLE },
- { ID_LI, "Library", "libraries", 0 },
- { ID_LS, "FreestyleLineStyle", "linestyles", IDTYPE_FLAGS_ISLINKABLE },
- { ID_LT, "Lattice", "lattices", IDTYPE_FLAGS_ISLINKABLE },
- { ID_MA, "Material", "materials", IDTYPE_FLAGS_ISLINKABLE },
- { ID_MB, "Metaball", "metaballs", IDTYPE_FLAGS_ISLINKABLE },
- { ID_MC, "MovieClip", "movieclips", IDTYPE_FLAGS_ISLINKABLE },
- { ID_ME, "Mesh", "meshes", IDTYPE_FLAGS_ISLINKABLE },
- { ID_MSK, "Mask", "masks", IDTYPE_FLAGS_ISLINKABLE },
- { ID_NT, "NodeTree", "node_groups", IDTYPE_FLAGS_ISLINKABLE },
- { ID_OB, "Object", "objects", IDTYPE_FLAGS_ISLINKABLE },
- { ID_PA, "ParticleSettings", "particles", 0 },
- { ID_PAL, "Palettes", "palettes", IDTYPE_FLAGS_ISLINKABLE },
- { ID_PC, "PaintCurve", "paint_curves", IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCE, "Scene", "scenes", IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCR, "Screen", "screens", 0 },
- { ID_SEQ, "Sequence", "sequences", 0 }, /* not actually ID data */
- { ID_SPK, "Speaker", "speakers", IDTYPE_FLAGS_ISLINKABLE },
- { ID_SO, "Sound", "sounds", IDTYPE_FLAGS_ISLINKABLE },
- { ID_TE, "Texture", "textures", IDTYPE_FLAGS_ISLINKABLE },
- { ID_TXT, "Text", "texts", IDTYPE_FLAGS_ISLINKABLE },
- { ID_VF, "VFont", "fonts", IDTYPE_FLAGS_ISLINKABLE },
- { ID_WO, "World", "worlds", IDTYPE_FLAGS_ISLINKABLE },
- { ID_WM, "WindowManager", "window_managers", 0 },
+ { ID_AC, "Action", "actions", BLF_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_AR, "Armature", "armatures", BLF_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_BR, "Brush", "brushes", BLF_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_CA, "Camera", "cameras", BLF_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_CU, "Curve", "curves", BLF_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_GD, "GPencil", "grease_pencil", BLF_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
+ { ID_GR, "Group", "groups", BLF_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_ID, "ID", "ids", BLF_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
+ { ID_IM, "Image", "images", BLF_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
+ { ID_KE, "Key", "shape_keys", BLF_I18NCONTEXT_ID_SHAPEKEY, 0 },
+ { ID_LA, "Lamp", "lamps", BLF_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_LI, "Library", "libraries", BLF_I18NCONTEXT_ID_LIBRARY, 0 },
+ { ID_LS, "FreestyleLineStyle", "linestyles", BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_LT, "Lattice", "lattices", BLF_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_MA, "Material", "materials", BLF_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_MB, "Metaball", "metaballs", BLF_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_MC, "MovieClip", "movieclips", BLF_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_ME, "Mesh", "meshes", BLF_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_MSK, "Mask", "masks", BLF_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_NT, "NodeTree", "node_groups", BLF_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_OB, "Object", "objects", BLF_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_PA, "ParticleSettings", "particles", BLF_I18NCONTEXT_ID_PARTICLESETTINGS, 0 },
+ { ID_PAL, "Palettes", "palettes", BLF_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_PC, "PaintCurve", "paint_curves", BLF_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_SCE, "Scene", "scenes", BLF_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_SCR, "Screen", "screens", BLF_I18NCONTEXT_ID_SCREEN, 0 },
+ { ID_SEQ, "Sequence", "sequences", BLF_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
+ { ID_SPK, "Speaker", "speakers", BLF_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_SO, "Sound", "sounds", BLF_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_TE, "Texture", "textures", BLF_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_TXT, "Text", "texts", BLF_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_VF, "VFont", "fonts", BLF_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_WO, "World", "worlds", BLF_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
+ { ID_WM, "WindowManager", "window_managers", BLF_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
};
static IDType *idtype_from_name(const char *str)
@@ -176,6 +180,19 @@ const char *BKE_idcode_to_name_plural(int code)
}
/**
+ * Convert an idcode into its translations' context.
+ *
+ * \param code The code to convert.
+ * \return A static string representing the i18n context of the code.
+ */
+const char *BKE_idcode_to_translation_context(int code)
+{
+ IDType *idt = idtype_from_code(code);
+ BLI_assert(idt);
+ return idt ? idt->i18n_context : BLF_I18NCONTEXT_DEFAULT;
+}
+
+/**
* Return an ID code and steps the index forward 1.
*
* \param index start as 0.
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 9b00a0150ad..d648db77186 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -75,6 +75,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
@@ -99,6 +100,12 @@
static SpinLock image_spin;
+/* prototypes */
+static size_t image_num_files(struct Image *ima);
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock);
+static void image_update_views_format(Image *ima, ImageUser *iuser);
+static void image_add_view(Image *ima, const char *viewname, const char *filepath);
+
/* max int, to indicate we don't store sequences in ibuf */
#define IMA_NO_INDEX 0x7FEFEFEF
@@ -257,6 +264,46 @@ static void image_free_cached_frames(Image *image)
}
}
+static void image_free_packedfiles(Image *ima)
+{
+ while (ima->packedfiles.last) {
+ ImagePackedFile *imapf = ima->packedfiles.last;
+ if (imapf->packedfile) {
+ freePackedFile(imapf->packedfile);
+ }
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
+ }
+}
+
+void BKE_image_free_packedfiles(Image *ima)
+{
+ image_free_packedfiles(ima);
+}
+
+static void image_free_views(Image *ima)
+{
+ BLI_freelistN(&ima->views);
+}
+
+void BKE_image_free_views(Image *image)
+{
+ image_free_views(image);
+}
+
+static void image_free_anims(Image *ima)
+{
+ while (ima->anims.last) {
+ ImageAnim *ia = ima->anims.last;
+ if (ia->anim) {
+ IMB_free_anim(ia->anim);
+ ia->anim = NULL;
+ }
+ BLI_remlink(&ima->anims, ia);
+ MEM_freeN(ia);
+ }
+}
+
/**
* Simply free the image data from memory,
* on display the image can load again (except for render buffers).
@@ -265,8 +312,7 @@ void BKE_image_free_buffers(Image *ima)
{
image_free_cached_frames(ima);
- if (ima->anim) IMB_free_anim(ima->anim);
- ima->anim = NULL;
+ image_free_anims(ima);
if (ima->rr) {
RE_FreeRenderResult(ima->rr);
@@ -290,11 +336,10 @@ void BKE_image_free(Image *ima)
int a;
BKE_image_free_buffers(ima);
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- }
- BKE_icon_delete(&ima->id);
+
+ image_free_packedfiles(ima);
+
+ BKE_icon_id_delete(&ima->id);
ima->id.icon_id = 0;
BKE_previewimg_free(&ima->preview);
@@ -305,6 +350,9 @@ void BKE_image_free(Image *ima)
ima->renders[a] = NULL;
}
}
+
+ image_free_views(ima);
+ MEM_freeN(ima->stereo3d_format);
}
/* only image block itself */
@@ -328,7 +376,9 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
ima->flag |= IMA_VIEW_AS_RENDER;
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
+
return ima;
}
@@ -359,6 +409,22 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
}
}
+static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
+{
+ const ImagePackedFile *imapf_src;
+
+ BLI_listbase_clear(lb_dst);
+ for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
+ ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
+ BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath));
+
+ if (imapf_src->packedfile)
+ imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
+
+ BLI_addtail(lb_dst, imapf_dst);
+ }
+}
+
/* empty image block, of similar type and filename */
Image *BKE_image_copy(Main *bmain, Image *ima)
{
@@ -381,8 +447,10 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings);
- if (ima->packedfile)
- nima->packedfile = dupPackedFile(ima->packedfile);
+ copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
+
+ nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
+ BLI_duplicatelist(&nima->views, &ima->views);
if (ima->id.lib) {
BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
@@ -686,7 +754,9 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id));
if (BLI_path_cmp(strtest, str) == 0) {
- if (ima->anim == NULL || ima->id.us == 0) {
+ if ((BKE_image_has_anim(ima) == false) ||
+ (ima->id.us == 0))
+ {
ima->id.us++; /* officially should not, it doesn't link here! */
if (ima->ok == 0)
ima->ok = IMA_OK;
@@ -774,13 +844,14 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
}
/* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4])
+Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
if (ima) {
- ImBuf *ibuf;
+ size_t view_id;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
/* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
@@ -790,13 +861,21 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
ima->gen_depth = depth;
copy_v4_v4(ima->gen_color, color);
- ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ for (view_id = 0; view_id < 2; view_id++) {
+ ImBuf *ibuf;
+ ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
- /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
- IMB_freeImBuf(ibuf);
+ /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
+ IMB_freeImBuf(ibuf);
+ if (!stereo3d) break;
+
+ image_add_view(ima, names[view_id], "");
+ }
ima->ok = IMA_OK_LOADED;
+ if (stereo3d)
+ ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW;
}
return ima;
@@ -805,12 +884,16 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
/* Create an image image from ibuf. The refcount of ibuf is increased,
* caller should take care to drop its reference by calling
* IMB_freeImBuf if needed. */
-Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
+Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima;
- ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ if (name == NULL) {
+ name = BLI_path_basename(ibuf->name);
+ }
+
+ ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
if (ima) {
BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
@@ -821,18 +904,79 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
return ima;
}
+/* packs rects from memory as PNG
+ * convert multiview images to R_IMF_VIEWS_INDIVIDUAL
+ */
+static void image_memorypack_multiview(Image *ima)
+{
+ ImageView *iv;
+ size_t i;
+
+ image_free_packedfiles(ima);
+
+ for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+
+ ibuf->ftype = PNG;
+ ibuf->planes = R_IMF_PLANES_RGBA;
+
+ /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
+ if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
+ BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
+ }
+
+ IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem);
+
+ if (ibuf->encodedbuffer == NULL) {
+ printf("memory save for pack error\n");
+ IMB_freeImBuf(ibuf);
+ image_free_packedfiles(ima);
+ return;
+ }
+ else {
+ ImagePackedFile *imapf;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ ibuf->encodedbuffer = NULL;
+ ibuf->encodedsize = 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+ }
+ IMB_freeImBuf(ibuf);
+ }
+
+ if (ima->source == IMA_SRC_GENERATED) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+ ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
+}
+
/* packs rect from memory as PNG */
void BKE_image_memorypack(Image *ima)
{
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf;
- if (ibuf == NULL)
+ if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ image_memorypack_multiview(ima);
return;
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
}
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+
+ if (ibuf == NULL)
+ return;
+
+ image_free_packedfiles(ima);
+
ibuf->ftype = PNG;
ibuf->planes = R_IMF_PLANES_RGBA;
@@ -841,11 +985,17 @@ void BKE_image_memorypack(Image *ima)
printf("memory save for pack error\n");
}
else {
+ ImagePackedFile *imapf;
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = ibuf->encodedbuffer;
pf->size = ibuf->encodedsize;
- ima->packedfile = pf;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
ibuf->encodedbuffer = NULL;
ibuf->encodedsize = 0;
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -859,6 +1009,53 @@ void BKE_image_memorypack(Image *ima)
IMB_freeImBuf(ibuf);
}
+void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles == 1) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFile(reports, ima->name, basepath);
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ else {
+ ImageView *iv;
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ }
+}
+
+void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != 1) {
+ BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
+ }
+ else {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFileMemory(data, data_len);
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+}
+
void BKE_image_tag_time(Image *ima)
{
ima->lastused = PIL_check_seconds_timer_i();
@@ -1203,7 +1400,7 @@ char BKE_imtype_valid_depths(const char imtype)
case R_IMF_IMTYPE_OPENEXR:
return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
case R_IMF_IMTYPE_MULTILAYER:
- return R_IMF_CHAN_DEPTH_32;
+ return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
/* eeh, cineon does some strange 10bits per channel */
case R_IMF_IMTYPE_DPX:
return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_10 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
@@ -1259,7 +1456,7 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else return R_IMF_IMTYPE_INVALID;
}
-static bool image_path_ensure_ext(char *string, const char imtype, const ImageFormatData *im_format)
+static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
{
const char *extension = NULL;
const char *extension_test;
@@ -1311,7 +1508,7 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
#endif
#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
if (!BLI_testextensie(string, extension_test = ".exr"))
extension = extension_test;
}
@@ -1369,14 +1566,14 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
}
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
+int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
{
- return image_path_ensure_ext(string, im_format->imtype, im_format);
+ return do_add_image_extension(string, im_format->imtype, im_format);
}
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
{
- return image_path_ensure_ext(string, imtype, NULL);
+ return do_add_image_extension(string, imtype, NULL);
}
void BKE_imformat_defaults(ImageFormatData *im_format)
@@ -1861,28 +2058,67 @@ void BKE_image_stamp_buf(
#undef BUFF_MARGIN_Y
}
-void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf)
+void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr)
{
- struct StampData stamp_data;
+ struct StampData *stamp_data;
- if (!ibuf) return;
+ if (!(scene && scene->r.stamp & R_STAMP_ALL))
+ return;
- /* fill all the data values, no prefix */
- stampdata(scene, camera, &stamp_data, 0);
+ if (!rr->stamp_data) {
+ stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ else {
+ stamp_data = rr->stamp_data;
+ }
- if (stamp_data.file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data.file);
- if (stamp_data.note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data.note);
- if (stamp_data.date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data.date);
- if (stamp_data.marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data.marker);
- if (stamp_data.time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data.time);
- if (stamp_data.frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data.frame);
- if (stamp_data.camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data.camera);
- if (stamp_data.cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data.cameralens);
- if (stamp_data.scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data.scene);
- if (stamp_data.strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data.strip);
- if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime);
+ stampdata(scene, camera, stamp_data, 0);
+
+ if (!rr->stamp_data) {
+ rr->stamp_data = stamp_data;
+ }
}
+void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback)
+{
+ if (!callback || !stamp_data) {
+ return;
+ }
+
+#define CALL(member, value_str) \
+ if (stamp_data->member[0]) { \
+ callback(data, value_str, stamp_data->member); \
+ } ((void)0)
+
+ CALL(file, "File");
+ CALL(note, "Note");
+ CALL(date, "Date");
+ CALL(marker, "Marker");
+ CALL(time, "Time");
+ CALL(frame, "Frame");
+ CALL(camera, "Camera");
+ CALL(cameralens, "Lens");
+ CALL(scene, "Scene");
+ CALL(strip, "Strip");
+ CALL(rendertime, "RenderTime");
+
+#undef CALL
+}
+
+/* wrap for callback only */
+static void metadata_change_field(void *data, const char *propname, const char *propvalue)
+{
+ IMB_metadata_change_field(data, propname, propvalue);
+}
+
+void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
+{
+ struct StampData *stamp_data = rr->stamp_data;
+
+ BKE_stamp_info_callback(ibuf, stamp_data, metadata_change_field);
+}
+
+
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
{
int tot;
@@ -1908,14 +2144,12 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
/* note: imf->planes is ignored here, its assumed the image channels
* are already set */
-int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
{
char imtype = imf->imtype;
char compress = imf->compress;
char quality = imf->quality;
- int ok;
-
if (imtype == R_IMF_IMTYPE_IRIS) {
ibuf->ftype = IMAGIC;
}
@@ -1952,7 +2186,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
}
#endif
#ifdef WITH_OPENEXR
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
ibuf->ftype = OPENEXR;
if (imf->depth == R_IMF_CHAN_DEPTH_16)
ibuf->ftype |= OPENEXR_HALF;
@@ -2036,6 +2270,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
if (quality < 10) quality = 90;
ibuf->ftype = JPG | quality;
}
+}
+
+int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+{
+ int ok;
+
+ BKE_imbuf_write_prepare(ibuf, imf);
BLI_make_existing_file(name);
@@ -2070,18 +2311,18 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
return ok;
}
-int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
+int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
{
if (scene && scene->r.stamp & R_STAMP_ALL)
- BKE_imbuf_stamp_info(scene, camera, ibuf);
+ BKE_imbuf_stamp_info(rr, ibuf);
return BKE_imbuf_write(ibuf, name, imf);
}
-
-static void image_path_makepicstring(
+static void do_makepicstring(
char *string, const char *base, const char *relbase, int frame, const char imtype,
- const ImageFormatData *im_format, const short use_ext, const short use_frames)
+ const ImageFormatData *im_format, const short use_ext, const short use_frames,
+ const char *suffix)
{
if (string == NULL) return;
BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
@@ -2090,22 +2331,25 @@ static void image_path_makepicstring(
if (use_frames)
BLI_path_frame(string, frame, 4);
+ if (suffix)
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+
if (use_ext)
- image_path_ensure_ext(string, imtype, im_format);
+ do_add_image_extension(string, imtype, im_format);
}
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const ImageFormatData *im_format, const bool use_ext, const bool use_frames)
+ const ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix)
{
- image_path_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
}
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames)
+ const char imtype, const bool use_ext, const bool use_frames, const char *view)
{
- image_path_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view);
}
struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
@@ -2181,6 +2425,71 @@ Image *BKE_image_verify_viewer(int type, const char *name)
return ima;
}
+static void image_viewer_create_views(const RenderData *rd, Image *ima)
+{
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ image_add_view(ima, "", "");
+ }
+ else {
+ SceneRenderView *srv;
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ image_add_view(ima, srv->name, "");
+ }
+ }
+}
+
+/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
+void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
+{
+ bool do_reset;
+ const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0;
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+
+ if (BKE_scene_multiview_is_stereo3d(rd)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+
+ /* see if all scene render views are in the image view list */
+ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
+
+ /* multiview also needs to be sure all the views are synced */
+ if (is_multiview && !do_reset) {
+ SceneRenderView *srv;
+ ImageView *iv;
+
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name));
+ if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) {
+ do_reset = true;
+ break;
+ }
+ }
+ }
+
+ if (do_reset) {
+ BLI_spin_lock(&image_spin);
+
+ image_free_cached_frames(ima);
+ BKE_image_free_views(ima);
+
+ /* add new views */
+ image_viewer_create_views(rd, ima);
+
+ BLI_spin_unlock(&image_spin);
+ }
+
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+}
+
void BKE_image_walk_all_users(const Main *mainp, void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
@@ -2238,6 +2547,33 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat
}
}
+static void image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ RenderResult *rr = ima->rr;
+
+ iuser->multi_index = 0;
+ iuser->layer = iuser->view = 0;
+ iuser->passtype = SCE_PASS_COMBINED;
+
+ if (rr) {
+ RenderLayer *rl = rr->layers.first;
+
+ if (rl) {
+ RenderPass *rp = rl->passes.first;
+
+ if (rp)
+ iuser->passtype = rp->passtype;
+ }
+
+ BKE_image_multilayer_index(rr, iuser);
+ }
+}
+
+void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ image_init_imageuser(ima, iuser);
+}
+
void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
{
if (ima == NULL)
@@ -2248,8 +2584,13 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
switch (signal) {
case IMA_SIGNAL_FREE:
BKE_image_free_buffers(ima);
- if (iuser)
+
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_SRC_CHANGE:
if (ima->type == IMA_TYPE_UV_TEST)
@@ -2301,23 +2642,41 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_RELOAD:
/* try to repack file */
- if (ima->packedfile) {
- PackedFile *pf;
- pf = newPackedFile(NULL, ima->name, ID_BLEND_PATH(G.main, &ima->id));
- if (pf) {
- freePackedFile(ima->packedfile);
- ima->packedfile = pf;
- BKE_image_free_buffers(ima);
+ if (BKE_image_has_packedfile(ima)) {
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ /* in case there are new available files to be loaded */
+ image_free_packedfiles(ima);
+ BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id));
}
else {
- printf("ERROR: Image not available. Keeping packed image\n");
+ ImagePackedFile *imapf;
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ PackedFile *pf;
+ pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(G.main, &ima->id));
+ if (pf) {
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = pf;
+ }
+ else {
+ printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
+ }
+ }
}
+
+ if (BKE_image_has_packedfile(ima))
+ BKE_image_free_buffers(ima);
}
else
BKE_image_free_buffers(ima);
- if (iuser)
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_USER_NEW_IMAGE:
@@ -2325,8 +2684,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
iuser->ok = 1;
if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_MULTILAYER) {
- iuser->multi_index = 0;
- iuser->layer = iuser->pass = 0;
+ image_init_imageuser(ima, iuser);
}
}
}
@@ -2368,44 +2726,113 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
return NULL;
if (iuser) {
- short index = 0, rl_index = 0, rp_index;
+ short index = 0, rv_index, rl_index = 0;
+ bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
+
+ rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
+ if (RE_HasFakeLayer(rr)) rl_index += 1;
for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) {
- rp_index = 0;
- for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++, rp_index++)
- if (iuser->layer == rl_index && iuser->pass == rp_index)
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++) {
+ if (iuser->layer == rl_index &&
+ iuser->passtype == rpass->passtype &&
+ rv_index == rpass->view_id)
+ {
break;
+ }
+ }
if (rpass)
break;
}
-
- if (rpass)
- iuser->multi_index = index;
- else
- iuser->multi_index = 0;
+ iuser->multi_index = (rpass ? index : 0);
}
+
if (rpass == NULL) {
rl = rr->layers.first;
if (rl)
rpass = rl->passes.first;
+
+ if (rpass && iuser)
+ iuser->passtype = rpass->passtype;
}
return rpass;
}
+void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
+{
+ if (iuser) {
+ bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO);
+ if (is_stereo) {
+ iuser->multi_index = iuser->multiview_eye;
+ }
+ else {
+ if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) {
+ iuser->multi_index = iuser->view = 0;
+ }
+ else {
+ iuser->multi_index = iuser->view;
+ }
+ }
+ }
+}
+
+/* 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! */
+/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
+bool BKE_image_is_multilayer(Image *ima)
+{
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ return true;
+ }
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr)
+{
+ if (rr) {
+ if (RE_RenderResult_is_stereo(rr)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1)
+ ima->flag |= IMA_IS_MULTIVIEW;
+ else
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+
RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
{
+ RenderResult *rr = NULL;
if (ima->rr) {
- return ima->rr;
+ rr = ima->rr;
}
else if (ima->type == IMA_TYPE_R_RESULT) {
if (ima->render_slot == ima->last_render_slot)
- return RE_AcquireResultRead(RE_GetRender(scene->id.name));
+ rr = RE_AcquireResultRead(RE_GetRender(scene->id.name));
else
- return ima->renders[ima->render_slot];
+ rr = ima->renders[ima->render_slot];
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, rr);
}
- else
- return NULL;
+
+ return rr;
}
void BKE_image_release_renderresult(Scene *scene, Image *ima)
@@ -2419,6 +2846,18 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
}
}
+bool BKE_image_is_openexr(struct Image *ima)
+{
+#ifdef WITH_OPENEXR
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ return BLI_testextensie(ima->name, ".exr");
+ }
+#else
+ UNUSED_VARS(ima);
+#endif
+ return false;
+}
+
void BKE_image_backup_render(Scene *scene, Image *ima)
{
/* called right before rendering, ima->renders contains render
@@ -2439,8 +2878,155 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
ima->last_render_slot = slot;
}
+/**************************** multiview save openexr *********************************/
+#ifdef WITH_OPENEXR
+static const char *image_get_view_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageView *iv = BLI_findlink(&ima->views, view_id);
+ return iv ? iv->name : "";
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static ImBuf *image_get_buffer_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageUser iuser = {0};
+
+ iuser.view = view_id;
+ iuser.ok = 1;
+
+ BKE_image_multiview_index(ima, &iuser);
+
+ return image_acquire_ibuf(ima, &iuser, NULL);
+}
+#endif /* WITH_OPENEXR */
+
+bool BKE_image_save_openexr_multiview(Image *ima, ImBuf *ibuf, const char *filepath, const int flags)
+{
+#ifdef WITH_OPENEXR
+ char name[FILE_MAX];
+ bool ok;
+
+ BLI_strncpy(name, filepath, sizeof(name));
+ BLI_path_abs(name, G.main->name);
+
+ ibuf->userdata = ima;
+ ok = IMB_exr_multiview_save(ibuf, name, flags, BLI_listbase_count(&ima->views), image_get_view_cb, image_get_buffer_cb);
+ ibuf->userdata = NULL;
+
+ return ok;
+#else
+ UNUSED_VARS(ima, ibuf, filepath, flags);
+ return false;
+#endif
+}
+
+/**************************** multiview load openexr *********************************/
+
+static void image_add_view(Image *ima, const char *viewname, const char *filepath)
+{
+ ImageView *iv;
+
+ iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
+ BLI_strncpy(iv->name, viewname, sizeof(iv->name));
+ BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath));
+
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+
+ if (STREQ(viewname, STEREO_LEFT_NAME)) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
+ ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name));
+
+ if (left_iv == NULL) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else {
+ BLI_insertlinkafter(&ima->views, left_iv, iv);
+ }
+ }
+ else {
+ BLI_addtail(&ima->views, iv);
+ }
+}
+
+#ifdef WITH_OPENEXR
+static void image_add_view_cb(void *base, const char *str)
+{
+ Image *ima = base;
+ image_add_view(ima, str, ima->name);
+}
+
+static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame)
+{
+ Image *ima = base;
+ size_t id;
+ bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ const char *colorspace = ima->colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
+ if (ibuf == NULL)
+ return;
+
+ id = BLI_findstringindex(&ima->views, str, offsetof(ImageView, name));
+
+ if (id == -1)
+ return;
+
+ if (ibuf->channels >= 3)
+ IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+ colorspace, to_colorspace, predivide);
+
+ image_assign_ibuf(ima, ibuf, id, frame);
+ IMB_freeImBuf(ibuf);
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static void image_update_multiview_flags(Image *ima)
+{
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+
+ if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)))
+ {
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+#endif /* WITH_OPENEXR */
+
/* after imbuf load, openexr type can return with a exrhandle open */
/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
+static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame)
+{
+ image_free_views(ima);
+
+ IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame);
+
+ image_update_multiview_flags(ima);
+
+ IMB_exr_close(ibuf->userdata);
+}
+#endif /* WITH_OPENEXR */
+
+/* after imbuf load, openexr type can return with a exrhandle open */
+/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
{
const char *colorspace = ima->colorspace_settings.name;
@@ -2448,21 +3034,23 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
-#ifdef WITH_OPENEXR
IMB_exr_close(ibuf->userdata);
-#endif
ibuf->userdata = NULL;
if (ima->rr)
ima->rr->framenr = framenr;
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, ima->rr);
}
+#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
{
/* preview is NULL when it has never been used as an icon before */
if (G.background == 0 && ima->preview == NULL)
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* fields */
if (ima->flag & IMA_FIELDS) {
@@ -2488,18 +3076,41 @@ static int imbuf_alpha_flags_for_image(Image *ima)
return flag;
}
-static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+/* the number of files will vary according to the stereo format */
+static size_t image_num_files(Image *ima)
+{
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BLI_listbase_count(&ima->views);
+ }
+}
+
+static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id, bool *r_assign)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
+ ImageUser iuser_t;
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
ima->lastframe = frame;
- BKE_image_user_file_path(iuser, ima, name);
+
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+ BKE_image_user_file_path(&iuser_t, ima, name);
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
@@ -2520,25 +3131,78 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
#ifdef WITH_OPENEXR
/* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, frame);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ image_create_multiview(ima, ibuf, frame);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, frame);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
else {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
}
#else
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
#endif
}
- else
- ima->ok = 0;
- if (iuser)
- iuser->ok = ima->ok;
+ return ibuf;
+}
+
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool assign = false;
+
+ if (!is_multiview) {
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
return ibuf;
}
@@ -2595,46 +3259,52 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
return ibuf;
}
-
-static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id)
{
struct ImBuf *ibuf = NULL;
+ ImageAnim *ia;
- ima->lastframe = frame;
+ ia = BLI_findlink(&ima->anims, view_id);
- if (ima->anim == NULL) {
+ if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
+ ImageUser iuser_t;
+
if (ima->flag & IMA_DEINTERLACE) {
flags |= IB_animdeinterlace;
}
- BKE_image_user_file_path(iuser, ima, str);
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, str);
/* FIXME: make several stream accessible in image editor, too*/
- ima->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
+ ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
/* let's initialize this user */
- if (ima->anim && iuser && iuser->frames == 0)
- iuser->frames = IMB_anim_get_duration(ima->anim,
+ if (ia->anim && iuser && iuser->frames == 0)
+ iuser->frames = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
}
- if (ima->anim) {
- int dur = IMB_anim_get_duration(ima->anim,
+ if (ia->anim) {
+ int dur = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
int fra = frame - 1;
if (fra < 0) fra = 0;
if (fra > (dur - 1)) fra = dur - 1;
ibuf = IMB_makeSingleUser(
- IMB_anim_absolute(ima->anim, fra,
+ IMB_anim_absolute(ia->anim, fra,
IMB_TC_RECORD_RUN,
IMB_PROXY_NONE));
if (ibuf) {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
}
else
ima->ok = 0;
@@ -2642,67 +3312,227 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
else
ima->ok = 0;
+ return ibuf;
+}
+
+static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ size_t i;
+
+ if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) {
+ image_free_anims(ima);
+
+ for (i = 0; i < totfiles; i++) {
+ /* allocate the ImageAnim */
+ ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim");
+ BLI_addtail(&ima->anims, ia);
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_movie_single(ima, iuser, frame, 0);
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ else {
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+ ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
+ }
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ else {
+ ima->ok = 0;
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
+
if (iuser)
iuser->ok = ima->ok;
return ibuf;
}
-/* warning, 'iuser' can be NULL */
-static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+static ImBuf *load_image_single(
+ Image *ima, ImageUser *iuser, int cfra,
+ const size_t view_id,
+ const bool has_packed,
+ bool *r_assign)
{
- struct ImBuf *ibuf;
- char str[FILE_MAX];
- int assign = 0, flag;
-
- /* always ensure clean ima */
- BKE_image_free_buffers(ima);
+ char filepath[FILE_MAX];
+ struct ImBuf *ibuf = NULL;
+ int flag;
/* is there a PackedFile with this image ? */
- if (ima->packedfile) {
+ if (has_packed) {
+ ImagePackedFile *imapf;
+
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
- ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag,
- ima->colorspace_settings.name, "<packed data>");
+ imapf = BLI_findlink(&ima->packedfiles, view_id);
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory(
+ (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
+ ima->colorspace_settings.name, "<packed data>");
+ }
}
else {
+ ImageUser iuser_t;
+
flag = IB_rect | IB_multilayer | IB_metadata;
flag |= imbuf_alpha_flags_for_image(ima);
- /* get the right string */
+ /* get the correct filepath */
BKE_image_user_frame_calc(iuser, cfra, 0);
- BKE_image_user_file_path(iuser, ima, str);
+
+ if (iuser)
+ iuser_t = *iuser;
+ else
+ iuser_t.framenr = ima->lastframe;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, filepath);
/* read ibuf */
- ibuf = IMB_loadiffname(str, flag, ima->colorspace_settings.name);
+ ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name);
}
if (ibuf) {
- /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+#ifdef WITH_OPENEXR
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, cfra);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ image_create_multiview(ima, ibuf, cfra);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, cfra);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
- else {
+ else
+#endif
+ {
image_initialize_after_load(ima, ibuf);
- assign = 1;
+ *r_assign = true;
/* check if the image is a font image... */
detectBitmapFont(ibuf);
/* make packed file for autopack */
- if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK))
- ima->packedfile = newPackedFile(NULL, str, ID_BLEND_PATH(G.main, &ima->id));
+ if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath));
+ imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id));
+ }
}
}
- else
+ else {
ima->ok = 0;
+ }
- if (assign)
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ return ibuf;
+}
+
+/* warning, 'iuser' can be NULL
+ * note: Image->views was already populated (in image_update_views_format)
+ */
+static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+{
+ struct ImBuf *ibuf = NULL;
+ bool assign = false;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool has_packed = BKE_image_has_packedfile(ima);
+
+ /* always ensure clean ima */
+ BKE_image_free_buffers(ima);
+
+ /* this should never happen, but just playing safe */
+ if (has_packed) {
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ image_free_packedfiles(ima);
+ has_packed = false;
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+ BLI_assert(totviews > 0);
+
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
+
+ /* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
+ ibuf_arr[0] && totfiles == 1 && totviews >= 2)
+ {
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+
+ /* return the original requested ImBuf */
+ i = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0;
+ ibuf = ibuf_arr[i];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
if (iuser)
iuser->ok = ima->ok;
@@ -2749,37 +3579,43 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
/* showing RGBA result itself (from compo/sequence) or
* like exr, using layers etc */
/* always returns a single ibuf, also during render progress */
-static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
{
Render *re;
RenderResult rres;
+ RenderView *rv;
float *rectf, *rectz;
unsigned int *rect;
float dither;
- int channels, layer, pass;
+ int channels, layer, passtype;
ImBuf *ibuf;
int from_render = (ima->render_slot == ima->last_render_slot);
+ int actview;
bool byte_buffer_in_display_space = false;
if (!(iuser && iuser->scene))
return NULL;
/* if we the caller is not going to release the lock, don't give the image */
- if (!lock_r)
+ if (!r_lock)
return NULL;
re = RE_GetRender(iuser->scene->id.name);
channels = 4;
layer = iuser->layer;
- pass = iuser->pass;
+ passtype = iuser->passtype;
+ actview = iuser->view;
+
+ if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO))
+ actview = iuser->multiview_eye;
if (from_render) {
- RE_AcquireResultImage(re, &rres);
+ RE_AcquireResultImage(re, &rres, actview);
}
else if (ima->renders[ima->render_slot]) {
rres = *(ima->renders[ima->render_slot]);
- rres.have_combined = rres.rectf != NULL;
+ rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
memset(&rres, 0, sizeof(RenderResult));
@@ -2790,16 +3626,30 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return NULL;
}
- /* release is done in BKE_image_release_ibuf using lock_r */
+ /* release is done in BKE_image_release_ibuf using r_lock */
if (from_render) {
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = re;
+ *r_lock = re;
+ rv = NULL;
+ }
+ else {
+ rv = BLI_findlink(&rres.views, actview);
+ if (rv == NULL)
+ rv = rres.views.first;
}
/* this gives active layer, composite or sequence result */
- rect = (unsigned int *)rres.rect32;
- rectf = rres.rectf;
- rectz = rres.rectz;
+ if (rv == NULL) {
+ rect = (unsigned int *)rres.rect32;
+ rectf = rres.rectf;
+ rectz = rres.rectz;
+ }
+ else {
+ rect = (unsigned int *)rv->rect32;
+ rectf = rv->rectf;
+ rectz = rv->rectz;
+ }
+
dither = iuser->scene->r.dither_intensity;
/* combined layer gets added as first layer */
@@ -2819,24 +3669,27 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
if (rl) {
RenderPass *rpass;
- /* there's no combined pass, is in renderlayer itself */
- if (pass == 0) {
- rectf = rl->rectf;
- if (rectf == NULL) {
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ if (passtype == rpass->passtype &&
+ actview == rpass->view_id)
+ {
+ break;
+ }
+ }
+
+ if (rpass) {
+ channels = rpass->channels;
+ rectf = rpass->rect;
+
+ if (!rectf) {
/* Happens when Save Buffers is enabled.
* Use display buffer stored in the render layer.
*/
rect = (unsigned int *) rl->display_buffer;
byte_buffer_in_display_space = true;
}
- }
- else {
- rpass = BLI_findlink(&rl->passes, pass - 1);
- if (rpass) {
- channels = rpass->channels;
- rectf = rpass->rect;
- dither = 0.0f; /* don't dither passes */
- }
+
+ dither = 0.0f; /* don't dither passes */
}
for (rpass = rl->passes.first; rpass; rpass = rpass->next)
@@ -2925,9 +3778,31 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return ibuf;
}
+static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
+{
+ const bool is_multilayer = BKE_image_is_multilayer(ima);
+ const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
+ int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
+
+ if (is_multilayer) {
+ return iuser ? iuser->multi_index : index;
+ }
+ else if (is_backdrop) {
+ if ((ima->flag & IMA_IS_STEREO)) {
+ /* backdrop hackaround (since there is no iuser */
+ return ima->eye;
+ }
+ }
+ else if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ return iuser ? iuser->multi_index : index;
+ }
+
+ return index;
+}
+
static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
- int frame = 0, index = 0;
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
@@ -2939,7 +3814,6 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
}
}
@@ -2956,12 +3830,12 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
@@ -2970,7 +3844,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame) {
@@ -2990,18 +3864,17 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
else if (ima->type == IMA_TYPE_MULTILAYER)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
@@ -3037,13 +3910,13 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
*
* not thread-safe, so callee should worry about thread locks
*/
-static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf = NULL;
int frame = 0, index = 0;
- if (lock_r)
- *lock_r = NULL;
+ if (r_lock)
+ *r_lock = NULL;
/* quick reject tests */
if (!image_quick_test(ima, iuser))
@@ -3085,31 +3958,31 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
if (ima->gen_depth == 0) ima->gen_depth = 24;
ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
ima->gen_color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ image_assign_ibuf(ima, ibuf, index, 0);
ima->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
if (ima->type == IMA_TYPE_R_RESULT) {
/* always verify entirely, and potentially
* returns pointer to release later */
- ibuf = image_get_render_result(ima, iuser, lock_r);
+ ibuf = image_get_render_result(ima, iuser, r_lock);
}
else if (ima->type == IMA_TYPE_COMPOSITE) {
/* requires lock/unlock, otherwise don't return image */
- if (lock_r) {
+ if (r_lock) {
/* unlock in BKE_image_release_ibuf */
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = ima;
+ *r_lock = ima;
/* XXX anim play for viewer nodes not yet supported */
frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
/* fake ibuf, will be filled in compositor */
- ibuf = IMB_allocImBuf(256, 256, 32, IB_rect);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
+ image_assign_ibuf(ima, ibuf, index, frame);
}
}
}
@@ -3133,13 +4006,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
*
* references the result, BKE_image_release_ibuf should be used to de-reference
*/
-ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf;
BLI_spin_lock(&image_spin);
- ibuf = image_acquire_ibuf(ima, iuser, lock_r);
+ ibuf = image_acquire_ibuf(ima, iuser, r_lock);
BLI_spin_unlock(&image_spin);
@@ -3409,7 +4282,13 @@ void BKE_image_update_frame(const Main *bmain, int cfra)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
- BLI_strncpy(filepath, ima->name, FILE_MAX);
+ if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) {
+ ImageView *iv = BLI_findlink(&ima->views, iuser->view);
+ BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
+ }
if (ima->source == IMA_SRC_SEQUENCE) {
char head[FILE_MAX], tail[FILE_MAX];
@@ -3545,6 +4424,16 @@ int BKE_image_sequence_guess_offset(Image *image)
return atoi(num);
}
+bool BKE_image_has_anim(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->anims) == false);
+}
+
+bool BKE_image_has_packedfile(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->packedfiles) == false);
+}
+
/**
* Checks the image buffer changes (not keyframed values)
*
@@ -3675,3 +4564,88 @@ ImBuf *BKE_image_get_first_ibuf(Image *image)
return ibuf;
}
+
+static void image_update_views_format(Image *ima, ImageUser *iuser)
+{
+ SceneRenderView *srv;
+ ImageView *iv;
+ Scene *scene = iuser->scene;
+ const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
+ ((ima->flag & IMA_USE_VIEWS) != 0);
+
+ /* reset the image views */
+ BKE_image_free_views(ima);
+
+ if (!is_multiview) {
+ goto monoview;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ size_t i;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ ima->flag |= IMA_IS_MULTIVIEW;
+ ima->flag |= IMA_IS_STEREO;
+
+ for (i = 0; i < 2; i++) {
+ image_add_view(ima, names[i], ima->name);
+ }
+ return;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ char prefix[FILE_MAX] = {'\0'};
+ char *name = ima->name;
+ const char *ext = NULL;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] == '\0') {
+ goto monoview;
+ }
+
+ /* create all the image views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ char filepath[FILE_MAX];
+ BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext);
+ image_add_view(ima, srv->name, filepath);
+ }
+ }
+
+ /* check if the files are all available */
+ iv = ima->views.last;
+ while (iv) {
+ int file;
+ char str[FILE_MAX];
+
+ BLI_strncpy(str, iv->filepath, sizeof(str));
+ BLI_path_abs(str, G.main->name);
+
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ ImageView *iv_del = iv;
+ iv = iv->prev;
+ BLI_remlink(&ima->views, iv_del);
+ MEM_freeN(iv_del);
+ }
+ else {
+ iv = iv->prev;
+ close(file);
+ }
+ }
+
+ /* all good */
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+ if (BKE_scene_multiview_is_stereo3d(&scene->r))
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+monoview:
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 09ce9484a69..6d37f3ae006 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1712,7 +1712,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check if object has any animation data */
if (ob->nlastrips.first) {
/* Add AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
/* IPO first to take into any non-NLA'd Object Animation */
if (ob->ipo) {
@@ -1735,7 +1735,7 @@ void do_versions_ipos_to_animato(Main *main)
}
else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Action first - so that Action name get conserved */
if (ob->action) {
@@ -1776,7 +1776,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check PoseChannels for constraints with local data */
if (ob->pose) {
/* Verify if there's AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
@@ -1802,7 +1802,7 @@ void do_versions_ipos_to_animato(Main *main)
*/
if (con->ipo) {
/* Verify if there's AnimData block, just in case */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
/* although this was the constraint's local IPO, we still need to provide con
* so that drivers can be added properly...
@@ -1819,7 +1819,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check constraint channels - we need to remove them anyway... */
if (ob->constraintChannels.first) {
/* Verify if there's AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
/* get pointer to next Constraint Channel */
@@ -1857,7 +1857,7 @@ void do_versions_ipos_to_animato(Main *main)
*/
if (key->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Shapekey data... */
ipo_to_animdata(id, key->ipo, NULL, NULL, NULL);
@@ -1879,7 +1879,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (ma->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Material data... */
ipo_to_animdata(id, ma->ipo, NULL, NULL, NULL);
@@ -1901,7 +1901,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (wo->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert World data... */
ipo_to_animdata(id, wo->ipo, NULL, NULL, NULL);
@@ -1921,7 +1921,7 @@ void do_versions_ipos_to_animato(Main *main)
if (ed && ed->seqbasep) {
Sequence *seq;
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
SEQ_BEGIN(ed, seq)
{
@@ -1977,7 +1977,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (te->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Texture data... */
ipo_to_animdata(id, te->ipo, NULL, NULL, NULL);
@@ -1999,7 +1999,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (ca->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Camera data... */
ipo_to_animdata(id, ca->ipo, NULL, NULL, NULL);
@@ -2021,7 +2021,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (la->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Lamp data... */
ipo_to_animdata(id, la->ipo, NULL, NULL, NULL);
@@ -2043,7 +2043,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (cu->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Curve data... */
ipo_to_animdata(id, cu->ipo, NULL, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 560a3c0726b..8427b17c01a 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -77,7 +77,7 @@ void BKE_key_free(Key *key)
{
KeyBlock *kb;
- BKE_free_animdata((ID *)key);
+ BKE_animdata_free((ID *)key);
while ((kb = BLI_pophead(&key->block))) {
if (kb->data)
@@ -1002,7 +1002,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
k1 += elemsize;
}
}
- else k1 += elemsize;
+ else {
+ k1 += elemsize;
+ }
}
if (flagdo & 2) {
if (flagflo & 2) {
@@ -1390,25 +1392,37 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-Key *BKE_key_from_object(Object *ob)
+Key **BKE_key_from_object_p(Object *ob)
{
- if (ob == NULL) return NULL;
-
+ if (ob == NULL)
+ return NULL;
+
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- return me->key;
+ return &me->key;
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- return cu->key;
+ return &cu->key;
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- return lt->key;
+ return &lt->key;
}
return NULL;
}
+Key *BKE_key_from_object(Object *ob)
+{
+ Key **key_p;
+ key_p = BKE_key_from_object_p(ob);
+ if (key_p) {
+ return *key_p;
+ }
+
+ return NULL;
+}
+
KeyBlock *BKE_keyblock_add(Key *key, const char *name)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 93b9c22566d..44e35c645de 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -221,7 +221,7 @@ void BKE_lamp_free(Lamp *la)
if (mtex) MEM_freeN(mtex);
}
- BKE_free_animdata((ID *)la);
+ BKE_animdata_free((ID *)la);
curvemapping_free(la->curfalloff);
@@ -232,7 +232,7 @@ void BKE_lamp_free(Lamp *la)
}
BKE_previewimg_free(&la->preview);
- BKE_icon_delete(&la->id);
+ BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index fa62308ec53..86927609ff6 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,6 +53,7 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -307,7 +308,7 @@ void BKE_lattice_free(Lattice *lt)
/* free animation data */
if (lt->adt) {
- BKE_free_animdata(&lt->id);
+ BKE_animdata_free(&lt->id);
lt->adt = NULL;
}
}
@@ -725,8 +726,9 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
return false;
}
-void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, short defaxis)
+void curve_deform_verts(
+ Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
+ int numVerts, const char *vgroup, short defaxis)
{
Curve *cu;
int a;
@@ -1068,7 +1070,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1205,3 +1207,10 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Lattice *UNUSED(latt))
+{
+}
+
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index fa4f9c6ed52..b4bb07f0d3a 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -115,6 +115,8 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -291,7 +293,7 @@ bool id_make_local(ID *id, bool test)
/**
* Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true iff the block can be copied.
+ * newid, unless test. Returns true if the block can be copied.
*/
bool id_copy(ID *id, ID **newid, bool test)
{
@@ -384,7 +386,7 @@ bool id_copy(ID *id, ID **newid, bool test)
if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
return true;
case ID_LS:
- if (!test) *newid = (ID *)BKE_linestyle_copy((FreestyleLineStyle *)id);
+ if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
return true;
}
@@ -432,7 +434,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(id, &newid, false) && newid) {
/* copy animation actions too */
- BKE_copy_animdata_id_action(id);
+ BKE_animdata_copy_id_action(id);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
@@ -554,9 +556,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
Object *ob;
/* flag for full recalc */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
- if (ob->id.lib)
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->id.lib) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ }
+ }
DAG_id_type_tag(bmain, ID_OB);
}
@@ -610,13 +614,13 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->speaker);
lb[a++] = &(main->world);
+ lb[a++] = &(main->movieclip);
lb[a++] = &(main->screen);
lb[a++] = &(main->object);
lb[a++] = &(main->linestyle); /* referenced by scenes */
lb[a++] = &(main->scene);
lb[a++] = &(main->library);
lb[a++] = &(main->wm);
- lb[a++] = &(main->movieclip);
lb[a++] = &(main->mask);
lb[a] = NULL;
@@ -785,7 +789,7 @@ static void id_copy_animdata(ID *id, const bool do_action)
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_copy_animdata(iat->adt, do_action); /* could be set to false, need to investigate */
+ iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */
}
}
@@ -865,18 +869,24 @@ static void BKE_library_free(Library *lib)
static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL;
-void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) )
+void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) )
{
free_windowmanager_cb = func;
}
static void (*free_notifier_reference_cb)(const void *) = NULL;
-void set_free_notifier_reference_cb(void (*func)(const void *) )
+void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) )
{
free_notifier_reference_cb = func;
}
+static void (*free_editor_id_reference_cb)(const ID *) = NULL;
+
+void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
+{
+ free_editor_id_reference_cb = func;
+}
static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
{
@@ -1034,8 +1044,13 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb)
+ if (free_notifier_reference_cb) {
free_notifier_reference_cb(id);
+ }
+
+ if (free_editor_id_reference_cb) {
+ free_editor_id_reference_cb(id);
+ }
BLI_remlink(lb, id);
@@ -1070,8 +1085,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
- "EvaluationContext");
+ bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
@@ -1138,7 +1152,7 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
- MEM_freeN(mainvar->eval_ctx);
+ DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
@@ -1404,16 +1418,20 @@ void id_clear_lib_data(Main *bmain, ID *id)
/* internal bNodeTree blocks inside ID types below
* also stores id->lib, make sure this stays in sync.
*/
- switch (GS(id->name)) {
- case ID_SCE: ntree = ((Scene *)id)->nodetree; break;
- case ID_MA: ntree = ((Material *)id)->nodetree; break;
- case ID_LA: ntree = ((Lamp *)id)->nodetree; break;
- case ID_WO: ntree = ((World *)id)->nodetree; break;
- case ID_TE: ntree = ((Tex *)id)->nodetree; break;
- case ID_LS: ntree = ((FreestyleLineStyle *)id)->nodetree; break;
- }
- if (ntree)
+ ntree = ntreeFromID(id);
+
+ if (ntree) {
ntree->id.lib = NULL;
+ }
+
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->proxy_from != NULL) {
+ object->proxy_from->proxy = NULL;
+ object->proxy_from->proxy_group = NULL;
+ }
+ object->proxy = object->proxy_from = object->proxy_group = NULL;
+ }
}
/* next to indirect usage in read/writefile also in editobject.c scene.c */
@@ -1603,7 +1621,7 @@ void rename_id(ID *id, const char *name)
void name_uiprefix_id(char *name, const ID *id)
{
name[0] = id->lib ? 'L' : ' ';
- name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' ';
+ name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
strcpy(name + 3, id->name + 2);
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index b97bf0ed9b0..40db411ef4c 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -107,14 +107,11 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle)
linestyle->caps = LS_CAPS_BUTT;
}
-FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main)
+FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle;
- if (!main)
- main = G.main;
-
- linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(main, ID_LS, name);
+ linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name);
default_linestyle_settings(linestyle);
@@ -138,7 +135,7 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
MEM_freeN(linestyle->nodetree);
}
- BKE_free_animdata(&linestyle->id);
+ BKE_animdata_free(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
@@ -149,13 +146,13 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
-FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle)
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle)
{
FreestyleLineStyle *new_linestyle;
LineStyleModifier *m;
int a;
- new_linestyle = BKE_linestyle_new(linestyle->id.name + 2, NULL);
+ new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2);
BKE_linestyle_free(new_linestyle);
for (a = 0; a < MAX_MTEX; a++) {
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 83ca6cd8d72..dd179ff91d2 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_sequence_types.h"
+#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -181,6 +182,16 @@ void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay)
sizeof(masklay->name));
}
+void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, char *oldname, char *newname)
+{
+ BLI_strncpy(masklay->name, newname, sizeof(masklay->name));
+
+ BKE_mask_layer_unique_name(mask, masklay);
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
+}
+
MaskLayer *BKE_mask_layer_copy(MaskLayer *masklay)
{
MaskLayer *masklay_new;
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 387d093051e..13ec970c65c 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1360,6 +1360,9 @@ float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float x
case PROP_SHARP:
value_layer = value_layer * value_layer;
break;
+ case PROP_INVSQUARE:
+ value_layer = value_layer * (2.0f - value_layer);
+ break;
case PROP_LIN:
default:
/* nothing */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 9b682f101ad..283c7a6fc88 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -53,6 +53,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_animsys.h"
#include "BKE_displist.h"
@@ -66,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_curve.h"
+#include "BKE_editmesh.h"
+#include "BKE_font.h"
#include "GPU_material.h"
@@ -99,11 +102,11 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
if (ma->ramp_col) MEM_freeN(ma->ramp_col);
if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
- BKE_free_animdata((ID *)ma);
+ BKE_animdata_free((ID *)ma);
if (ma->preview)
BKE_previewimg_free(&ma->preview);
- BKE_icon_delete((struct ID *)ma);
+ BKE_icon_id_delete((struct ID *)ma);
ma->id.icon_id = 0;
/* is no lib link block, but material extension */
@@ -806,9 +809,13 @@ void assign_material_id(ID *id, Material *ma, short act)
if (act > MAXMAT) return;
if (act < 1) act = 1;
+ /* this is needed for Python overrides,
+ * we just have to take care that the UI can't do this */
+#if 0
/* prevent crashing when using accidentally */
BLI_assert(id->lib == NULL);
if (id->lib) return;
+#endif
/* test arraylens */
@@ -918,6 +925,35 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
test_object_materials(G.main, ob->data);
}
+
+void BKE_material_remap_object(Object *ob, const unsigned int *remap)
+{
+ Material ***matar = give_matarar(ob);
+ const short *totcol_p = give_totcolp(ob);
+
+ BLI_array_permute(ob->mat, ob->totcol, remap);
+
+ if (ob->matbits) {
+ BLI_array_permute(ob->matbits, ob->totcol, remap);
+ }
+
+ if (matar) {
+ BLI_array_permute(*matar, *totcol_p, remap);
+ }
+
+ if (ob->type == OB_MESH) {
+ BKE_mesh_material_remap(ob->data, remap, ob->totcol);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ BKE_curve_material_remap(ob->data, remap, ob->totcol);
+ }
+ else {
+ /* add support for this object data! */
+ BLI_assert(matar == NULL);
+ }
+}
+
+
/* XXX - this calls many more update calls per object then are needed, could be optimized */
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
{
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index ce20636233a..c09cd1aabdc 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -39,6 +39,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <float.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_material_types.h"
@@ -46,7 +47,6 @@
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
-
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -54,7 +54,6 @@
#include "BKE_global.h"
#include "BKE_main.h"
-/* #include "BKE_object.h" */
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
@@ -65,119 +64,6 @@
#include "BKE_object.h"
#include "BKE_material.h"
-/* Data types */
-
-typedef struct vertex { /* surface vertex */
- float co[3]; /* position and surface normal */
- float no[3];
-} VERTEX;
-
-typedef struct vertices { /* list of vertices in polygonization */
- int count, max; /* # vertices, max # allowed */
- VERTEX *ptr; /* dynamically allocated */
-} VERTICES;
-
-typedef struct corner { /* corner of a cube */
- int i, j, k; /* (i, j, k) is index within lattice */
- float co[3], value; /* location and function value */
- struct corner *next;
-} CORNER;
-
-typedef struct cube { /* partitioning cell (cube) */
- int i, j, k; /* lattice location of cube */
- CORNER *corners[8]; /* eight corners */
-} CUBE;
-
-typedef struct cubes { /* linked list of cubes acting as stack */
- CUBE cube; /* a single cube */
- struct cubes *next; /* remaining elements */
-} CUBES;
-
-typedef struct centerlist { /* list of cube locations */
- int i, j, k; /* cube location */
- struct centerlist *next; /* remaining elements */
-} CENTERLIST;
-
-typedef struct edgelist { /* list of edges */
- int i1, j1, k1, i2, j2, k2; /* edge corner ids */
- int vid; /* vertex id */
- struct edgelist *next; /* remaining elements */
-} EDGELIST;
-
-typedef struct intlist { /* list of integers */
- int i; /* an integer */
- struct intlist *next; /* remaining elements */
-} INTLIST;
-
-typedef struct intlists { /* list of list of integers */
- INTLIST *list; /* a list of integers */
- struct intlists *next; /* remaining elements */
-} INTLISTS;
-
-/* dividing scene using octal tree makes polygonisation faster */
-typedef struct ml_pointer {
- struct ml_pointer *next, *prev;
- struct MetaElem *ml;
-} ml_pointer;
-
-typedef struct octal_node {
- struct octal_node *nodes[8];/* children of current node */
- struct octal_node *parent; /* parent of current node */
- struct ListBase elems; /* ListBase of MetaElem pointers (ml_pointer) */
- float x_min, y_min, z_min; /* 1st border point */
- float x_max, y_max, z_max; /* 7th border point */
- float x, y, z; /* center of node */
- int pos, neg; /* number of positive and negative MetaElements in the node */
- int count; /* number of MetaElems, which belongs to the node */
-} octal_node;
-
-typedef struct octal_tree {
- struct octal_node *first; /* first node */
- int pos, neg; /* number of positive and negative MetaElements in the scene */
- short depth; /* number of scene subdivision */
-} octal_tree;
-
-struct pgn_elements {
- struct pgn_elements *next, *prev;
- char *data;
-};
-
-typedef struct process { /* parameters, function, storage */
- /* ** old G_mb contents ** */
- float thresh;
- int totelem;
- MetaElem **mainb;
- octal_tree *metaball_tree;
-
- /* ** old process contents ** */
-
- /* what happens here? floats, I think. */
- /* float (*function)(void); */ /* implicit surface function */
- float (*function)(struct process *, float, float, float);
- float size, delta; /* cube size, normal delta */
- int bounds; /* cube range within lattice */
- CUBES *cubes; /* active cubes */
- VERTICES vertices; /* surface vertices */
- CENTERLIST **centers; /* cube center hash table */
- CORNER **corners; /* corner value hash table */
- EDGELIST **edges; /* edge and vertex id hash table */
-
- /* Runtime things */
- int *indices;
- int totindex, curindex;
-
- int pgn_offset;
- struct pgn_elements *pgn_current;
- ListBase pgn_list;
-} PROCESS;
-
-/* Forward declarations */
-static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb);
-static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k);
-static CORNER *setcorner(PROCESS *process, int i, int j, int k);
-static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2,
- float p[3], MetaBall *mb, int f);
-
/* Functions */
void BKE_mball_unlink(MetaBall *mb)
@@ -197,7 +83,7 @@ void BKE_mball_free(MetaBall *mb)
BKE_mball_unlink(mb);
if (mb->adt) {
- BKE_free_animdata((ID *)mb);
+ BKE_animdata_free((ID *)mb);
mb->adt = NULL;
}
if (mb->mat) MEM_freeN(mb->mat);
@@ -558,1817 +444,6 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
return basis;
}
-
-/* ******************** ARITH ************************* */
-
-/* BASED AT CODE (but mostly rewritten) :
- * C code from the article
- * "An Implicit Surface Polygonizer"
- * by Jules Bloomenthal, jbloom@beauty.gmu.edu
- * in "Graphics Gems IV", Academic Press, 1994
- *
- * Authored by Jules Bloomenthal, Xerox PARC.
- * Copyright (c) Xerox Corporation, 1991. All rights reserved.
- * Permission is granted to reproduce, use and distribute this code for
- * any and all purposes, provided that this notice appears in all copies. */
-
-#define RES 12 /* # converge iterations */
-
-#define L 0 /* left direction: -x, -i */
-#define R 1 /* right direction: +x, +i */
-#define B 2 /* bottom direction: -y, -j */
-#define T 3 /* top direction: +y, +j */
-#define N 4 /* near direction: -z, -k */
-#define F 5 /* far direction: +z, +k */
-#define LBN 0 /* left bottom near corner */
-#define LBF 1 /* left bottom far corner */
-#define LTN 2 /* left top near corner */
-#define LTF 3 /* left top far corner */
-#define RBN 4 /* right bottom near corner */
-#define RBF 5 /* right bottom far corner */
-#define RTN 6 /* right top near corner */
-#define RTF 7 /* right top far corner */
-
-/* the LBN corner of cube (i, j, k), corresponds with location
- * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size) */
-
-#define HASHBIT (5)
-#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
-
-#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) )
-
-#define MB_BIT(i, bit) (((i) >> (bit)) & 1)
-#define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */
-
-
-/* **************** POLYGONIZATION ************************ */
-
-static void calc_mballco(MetaElem *ml, float vec[3])
-{
- if (ml->mat) {
- mul_m4_v3((float (*)[4])ml->mat, vec);
- }
-}
-
-static float densfunc(MetaElem *ball, float x, float y, float z)
-{
- float dist2;
- float dvec[3] = {x, y, z};
-
- mul_m4_v3((float (*)[4])ball->imat, dvec);
-
- switch (ball->type) {
- case MB_BALL:
- /* do nothing */
- break;
- case MB_TUBE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
- break;
- case MB_PLANE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
- if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
- else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
- else dvec[1] = 0.0;
- break;
- case MB_ELIPSOID:
- dvec[0] /= ball->expx;
- dvec[1] /= ball->expy;
- dvec[2] /= ball->expz;
- break;
- case MB_CUBE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
-
- if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
- else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
- else dvec[1] = 0.0;
-
- if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
- else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
- else dvec[2] = 0.0;
- break;
-
- /* *** deprecated, could be removed?, do-versioned at least *** */
- case MB_TUBEX:
- if (dvec[0] > ball->len) dvec[0] -= ball->len;
- else if (dvec[0] < -ball->len) dvec[0] += ball->len;
- else dvec[0] = 0.0;
- break;
- case MB_TUBEY:
- if (dvec[1] > ball->len) dvec[1] -= ball->len;
- else if (dvec[1] < -ball->len) dvec[1] += ball->len;
- else dvec[1] = 0.0;
- break;
- case MB_TUBEZ:
- if (dvec[2] > ball->len) dvec[2] -= ball->len;
- else if (dvec[2] < -ball->len) dvec[2] += ball->len;
- else dvec[2] = 0.0;
- break;
- /* *** end deprecated *** */
- }
-
- dist2 = 1.0f - (len_squared_v3(dvec) / ball->rad2);
-
- if ((ball->flag & MB_NEGATIVE) == 0) {
- return (dist2 < 0.0f) ? -0.5f : (ball->s * dist2 * dist2 * dist2) - 0.5f;
- }
- else {
- return (dist2 < 0.0f) ? 0.5f : 0.5f - (ball->s * dist2 * dist2 * dist2);
- }
-}
-
-static octal_node *find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth)
-{
- if (!depth) return node;
-
- if (z < node->z) {
- if (y < node->y) {
- if (x < node->x) {
- if (node->nodes[0])
- return find_metaball_octal_node(node->nodes[0], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[1])
- return find_metaball_octal_node(node->nodes[1], x, y, z, depth--);
- else
- return node;
- }
- }
- else {
- if (x < node->x) {
- if (node->nodes[3])
- return find_metaball_octal_node(node->nodes[3], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[2])
- return find_metaball_octal_node(node->nodes[2], x, y, z, depth--);
- else
- return node;
- }
- }
- }
- else {
- if (y < node->y) {
- if (x < node->x) {
- if (node->nodes[4])
- return find_metaball_octal_node(node->nodes[4], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[5])
- return find_metaball_octal_node(node->nodes[5], x, y, z, depth--);
- else
- return node;
- }
- }
- else {
- if (x < node->x) {
- if (node->nodes[7])
- return find_metaball_octal_node(node->nodes[7], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[6])
- return find_metaball_octal_node(node->nodes[6], x, y, z, depth--);
- else
- return node;
- }
- }
- }
-
- /* all cases accounted for */
- BLI_assert(0);
-}
-
-static float metaball(PROCESS *process, float x, float y, float z)
-/* float x, y, z; */
-{
- octal_tree *metaball_tree = process->metaball_tree;
- struct octal_node *node;
- struct ml_pointer *ml_p;
- float dens = 0;
- int a;
-
- if (process->totelem > 1) {
- node = find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth);
- if (node) {
- for (ml_p = node->elems.first; ml_p; ml_p = ml_p->next) {
- dens += densfunc(ml_p->ml, x, y, z);
- }
-
- dens += -0.5f * (metaball_tree->pos - node->pos);
- dens += 0.5f * (metaball_tree->neg - node->neg);
- }
- else {
- for (a = 0; a < process->totelem; a++) {
- dens += densfunc(process->mainb[a], x, y, z);
- }
- }
- }
- else {
- dens += densfunc(process->mainb[0], x, y, z);
- }
-
- return process->thresh - dens;
-}
-
-/* ******************************************** */
-
-static void accum_mballfaces(PROCESS *process, int i1, int i2, int i3, int i4)
-{
- int *newi, *cur;
- /* static int i = 0; I would like to delete altogether, but I don't dare to, yet */
-
- if (process->totindex == process->curindex) {
- process->totindex += 256;
- newi = MEM_mallocN(4 * sizeof(int) * process->totindex, "vertindex");
-
- if (process->indices) {
- memcpy(newi, process->indices, 4 * sizeof(int) * (process->totindex - 256));
- MEM_freeN(process->indices);
- }
- process->indices = newi;
- }
-
- cur = process->indices + 4 * process->curindex;
-
- /* displists now support array drawing, we treat tri's as fake quad */
-
- cur[0] = i1;
- cur[1] = i2;
- cur[2] = i3;
- if (i4 == 0)
- cur[3] = i3;
- else
- cur[3] = i4;
-
- process->curindex++;
-
-}
-
-/* ******************* MEMORY MANAGEMENT *********************** */
-static void *new_pgn_element(PROCESS *process, int size)
-{
- /* during polygonize 1000s of elements are allocated
- * and never freed in between. Freeing only done at the end.
- */
- int blocksize = 16384;
- void *adr;
-
- if (size > 10000 || size == 0) {
- printf("incorrect use of new_pgn_element\n");
- }
- else if (size == -1) {
- struct pgn_elements *cur = process->pgn_list.first;
- while (cur) {
- MEM_freeN(cur->data);
- cur = cur->next;
- }
- BLI_freelistN(&process->pgn_list);
-
- return NULL;
- }
-
- size = 4 * ( (size + 3) / 4);
-
- if (process->pgn_current) {
- if (size + process->pgn_offset < blocksize) {
- adr = (void *) (process->pgn_current->data + process->pgn_offset);
- process->pgn_offset += size;
- return adr;
- }
- }
-
- process->pgn_current = MEM_callocN(sizeof(struct pgn_elements), "newpgn");
- process->pgn_current->data = MEM_callocN(blocksize, "newpgn");
- BLI_addtail(&process->pgn_list, process->pgn_current);
-
- process->pgn_offset = size;
- return process->pgn_current->data;
-}
-
-static void freepolygonize(PROCESS *process)
-{
- MEM_freeN(process->corners);
- MEM_freeN(process->edges);
- MEM_freeN(process->centers);
-
- new_pgn_element(process, -1);
-
- if (process->vertices.ptr) {
- MEM_freeN(process->vertices.ptr);
- }
-}
-
-/**** Cubical Polygonization (optional) ****/
-
-#define LB 0 /* left bottom edge */
-#define LT 1 /* left top edge */
-#define LN 2 /* left near edge */
-#define LF 3 /* left far edge */
-#define RB 4 /* right bottom edge */
-#define RT 5 /* right top edge */
-#define RN 6 /* right near edge */
-#define RF 7 /* right far edge */
-#define BN 8 /* bottom near edge */
-#define BF 9 /* bottom far edge */
-#define TN 10 /* top near edge */
-#define TF 11 /* top far edge */
-
-static INTLISTS *cubetable[256];
-
-/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
-static int corner1[12] = {
- LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF
-};
-static int corner2[12] = {
- LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF
-};
-static int leftface[12] = {
- B, L, L, F, R, T, N, R, N, B, T, F
-};
-/* face on left when going corner1 to corner2 */
-static int rightface[12] = {
- L, T, N, L, B, R, R, F, B, F, N, T
-};
-/* face on right when going corner1 to corner2 */
-
-
-/* docube: triangulate the cube directly, without decomposition */
-
-static void docube(PROCESS *process, CUBE *cube, MetaBall *mb)
-{
- INTLISTS *polys;
- CORNER *c1, *c2;
- int i, index = 0, count, indexar[8];
-
- for (i = 0; i < 8; i++) {
- if (cube->corners[i]->value > 0.0f) {
- index += (1 << i);
- }
- }
-
- for (polys = cubetable[index]; polys; polys = polys->next) {
- INTLIST *edges;
-
- count = 0;
-
- for (edges = polys->list; edges; edges = edges->next) {
- c1 = cube->corners[corner1[edges->i]];
- c2 = cube->corners[corner2[edges->i]];
-
- indexar[count] = vertid(process, c1, c2, mb);
- count++;
- }
- if (count > 2) {
- switch (count) {
- case 3:
- accum_mballfaces(process, indexar[2], indexar[1], indexar[0], 0);
- break;
- case 4:
- if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- break;
- case 5:
- if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
-
- accum_mballfaces(process, indexar[4], indexar[3], indexar[0], 0);
- break;
- case 6:
- if (indexar[0] == 0) {
- accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]);
- }
- else {
- accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- }
- break;
- case 7:
- if (indexar[0] == 0) {
- accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]);
- }
- else {
- accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- }
-
- accum_mballfaces(process, indexar[6], indexar[5], indexar[0], 0);
-
- break;
- }
- }
- }
-}
-
-
-/* testface: given cube at lattice (i, j, k), and four corners of face,
- * if surface crosses face, compute other four corners of adjacent cube
- * and add new cube to cube stack */
-
-static void testface(PROCESS *process, int i, int j, int k, CUBE *old, int bit, int c1, int c2, int c3, int c4)
-{
- CUBE newc;
- CUBES *oldcubes = process->cubes;
- CORNER *corn1, *corn2, *corn3, *corn4;
- int n, pos;
-
- corn1 = old->corners[c1];
- corn2 = old->corners[c2];
- corn3 = old->corners[c3];
- corn4 = old->corners[c4];
-
- pos = corn1->value > 0.0f ? 1 : 0;
-
- /* test if no surface crossing */
- if ( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return;
- /* test if cube out of bounds */
- /*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/
- /* test if already visited (always as last) */
- if (setcenter(process, process->centers, i, j, k)) {
- return;
- }
-
- /* create new cube and add cube to top of stack: */
- process->cubes = (CUBES *) new_pgn_element(process, sizeof(CUBES));
- process->cubes->next = oldcubes;
-
- newc.i = i;
- newc.j = j;
- newc.k = k;
- for (n = 0; n < 8; n++) newc.corners[n] = NULL;
-
- newc.corners[FLIP(c1, bit)] = corn1;
- newc.corners[FLIP(c2, bit)] = corn2;
- newc.corners[FLIP(c3, bit)] = corn3;
- newc.corners[FLIP(c4, bit)] = corn4;
-
- if (newc.corners[0] == NULL) newc.corners[0] = setcorner(process, i, j, k);
- if (newc.corners[1] == NULL) newc.corners[1] = setcorner(process, i, j, k + 1);
- if (newc.corners[2] == NULL) newc.corners[2] = setcorner(process, i, j + 1, k);
- if (newc.corners[3] == NULL) newc.corners[3] = setcorner(process, i, j + 1, k + 1);
- if (newc.corners[4] == NULL) newc.corners[4] = setcorner(process, i + 1, j, k);
- if (newc.corners[5] == NULL) newc.corners[5] = setcorner(process, i + 1, j, k + 1);
- if (newc.corners[6] == NULL) newc.corners[6] = setcorner(process, i + 1, j + 1, k);
- if (newc.corners[7] == NULL) newc.corners[7] = setcorner(process, i + 1, j + 1, k + 1);
-
- process->cubes->cube = newc;
-}
-
-/* setcorner: return corner with the given lattice location
- * set (and cache) its function value */
-
-static CORNER *setcorner(PROCESS *process, int i, int j, int k)
-{
- /* for speed, do corner value caching here */
- CORNER *c;
- int index;
-
- /* does corner exist? */
- index = HASH(i, j, k);
- c = process->corners[index];
-
- for (; c != NULL; c = c->next) {
- if (c->i == i && c->j == j && c->k == k) {
- return c;
- }
- }
-
- c = (CORNER *) new_pgn_element(process, sizeof(CORNER));
-
- c->i = i;
- c->co[0] = ((float)i - 0.5f) * process->size;
- c->j = j;
- c->co[1] = ((float)j - 0.5f) * process->size;
- c->k = k;
- c->co[2] = ((float)k - 0.5f) * process->size;
- c->value = process->function(process, c->co[0], c->co[1], c->co[2]);
-
- c->next = process->corners[index];
- process->corners[index] = c;
-
- return c;
-}
-
-
-/* nextcwedge: return next clockwise edge from given edge around given face */
-
-static int nextcwedge(int edge, int face)
-{
- switch (edge) {
- case LB:
- return (face == L) ? LF : BN;
- case LT:
- return (face == L) ? LN : TF;
- case LN:
- return (face == L) ? LB : TN;
- case LF:
- return (face == L) ? LT : BF;
- case RB:
- return (face == R) ? RN : BF;
- case RT:
- return (face == R) ? RF : TN;
- case RN:
- return (face == R) ? RT : BN;
- case RF:
- return (face == R) ? RB : TF;
- case BN:
- return (face == B) ? RB : LN;
- case BF:
- return (face == B) ? LB : RF;
- case TN:
- return (face == T) ? LT : RN;
- case TF:
- return (face == T) ? RT : LF;
- }
- return 0;
-}
-
-
-/* otherface: return face adjoining edge that is not the given face */
-
-static int otherface(int edge, int face)
-{
- int other = leftface[edge];
- return face == other ? rightface[edge] : other;
-}
-
-
-/* makecubetable: create the 256 entry table for cubical polygonization */
-
-static void makecubetable(void)
-{
- static bool is_done = false;
- int i, e, c, done[12], pos[8];
-
- if (is_done) return;
- is_done = true;
-
- 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++)
- if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
- INTLIST *ints = NULL;
- INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist");
- int start = e, edge = e;
-
- /* get face that is to right of edge from pos to neg corner: */
- int face = pos[corner1[e]] ? rightface[e] : leftface[e];
-
- while (1) {
- edge = nextcwedge(edge, face);
- done[edge] = 1;
- if (pos[corner1[edge]] != pos[corner2[edge]]) {
- INTLIST *tmp = ints;
-
- ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist");
- ints->i = edge;
- ints->next = tmp; /* add edge to head of list */
-
- if (edge == start) break;
- face = otherface(edge, face);
- }
- }
- lists->list = ints; /* add ints to head of table entry */
- lists->next = cubetable[i];
- cubetable[i] = lists;
- }
- }
-}
-
-void BKE_mball_cubeTable_free(void)
-{
- int i;
- INTLISTS *lists, *nlists;
- INTLIST *ints, *nints;
-
- for (i = 0; i < 256; i++) {
- lists = cubetable[i];
- while (lists) {
- nlists = lists->next;
-
- ints = lists->list;
- while (ints) {
- nints = ints->next;
- MEM_freeN(ints);
- ints = nints;
- }
-
- MEM_freeN(lists);
- lists = nlists;
- }
- cubetable[i] = NULL;
- }
-}
-
-/**** Storage ****/
-
-/* setcenter: set (i, j, k) entry of table[]
- * return 1 if already set; otherwise, set and return 0 */
-
-static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k)
-{
- int index;
- CENTERLIST *newc, *l, *q;
-
- index = HASH(i, j, k);
- q = table[index];
-
- for (l = q; l != NULL; l = l->next) {
- if (l->i == i && l->j == j && l->k == k) return 1;
- }
-
- newc = (CENTERLIST *) new_pgn_element(process, sizeof(CENTERLIST));
- newc->i = i;
- newc->j = j;
- newc->k = k;
- newc->next = q;
- table[index] = newc;
-
- return 0;
-}
-
-
-/* setedge: set vertex id for edge */
-
-static void setedge(PROCESS *process,
- EDGELIST *table[],
- int i1, int j1,
- int k1, int i2,
- int j2, int k2,
- int vid)
-{
- unsigned int index;
- EDGELIST *newe;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
- newe = (EDGELIST *) new_pgn_element(process, sizeof(EDGELIST));
- newe->i1 = i1;
- newe->j1 = j1;
- newe->k1 = k1;
- newe->i2 = i2;
- newe->j2 = j2;
- newe->k2 = k2;
- newe->vid = vid;
- newe->next = table[index];
- table[index] = newe;
-}
-
-
-/* getedge: return vertex id for edge; return -1 if not set */
-
-static int getedge(EDGELIST *table[],
- int i1, int j1, int k1,
- int i2, int j2, int k2)
-{
- EDGELIST *q;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
- for (; q != NULL; q = q->next) {
- if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
- q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
- {
- return q->vid;
- }
- }
- return -1;
-}
-
-
-/**** Vertices ****/
-
-#undef R
-
-
-
-/* vertid: return index for vertex on edge:
- * c1->value and c2->value are presumed of different sign
- * return saved index if any; else compute vertex and save */
-
-/* addtovertices: add v to sequence of vertices */
-
-static void addtovertices(VERTICES *vertices, VERTEX v)
-{
- if (vertices->count == vertices->max) {
- int i;
- VERTEX *newv;
- vertices->max = vertices->count == 0 ? 10 : 2 * vertices->count;
- newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices");
-
- for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i];
-
- if (vertices->ptr != NULL) MEM_freeN(vertices->ptr);
- vertices->ptr = newv;
- }
- vertices->ptr[vertices->count++] = v;
-}
-
-/* vnormal: compute unit length surface normal at point */
-
-static void vnormal(PROCESS *process, const float point[3], float r_no[3])
-{
- const float delta = 0.2f * process->delta;
- const float f = process->function(process, point[0], point[1], point[2]);
-
- r_no[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- r_no[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- r_no[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
-#if 1
- normalize_v3(r_no);
-#else
- f = normalize_v3(r_no);
-
- if (0) {
- float tvec[3];
-
- delta *= 2.0f;
-
- f = process->function(process, point[0], point[1], point[2]);
-
- tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
- if (normalize_v3(tvec) != 0.0f) {
- add_v3_v3(r_no, tvec);
- normalize_v3(r_no);
- }
- }
-#endif
-}
-
-
-static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb)
-{
- VERTEX v;
- int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
-
- if (vid != -1) {
- return vid; /* previously computed */
- }
-
- converge(process, c1->co, c2->co, c1->value, c2->value, v.co, mb, 1); /* position */
- vnormal(process, v.co, v.no);
-
- addtovertices(&process->vertices, v); /* save vertex */
- vid = process->vertices.count - 1;
- setedge(process, process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
-
- return vid;
-}
-
-
-/* converge: from two points of differing sign, converge to zero crossing */
-/* watch it: p1 and p2 are used to calculate */
-static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2,
- float p[3], MetaBall *mb, int f)
-{
- int i = 0;
- float pos[3], neg[3];
- float positive = 0.0f, negative = 0.0f;
- float dvec[3];
-
- if (v1 < 0) {
- copy_v3_v3(pos, p2);
- copy_v3_v3(neg, p1);
- positive = v2;
- negative = v1;
- }
- else {
- copy_v3_v3(pos, p1);
- copy_v3_v3(neg, p2);
- positive = v1;
- negative = v2;
- }
-
- sub_v3_v3v3(dvec, pos, neg);
-
-/* Approximation by linear interpolation is faster then binary subdivision,
- * but it results sometimes (mb->thresh < 0.2) into the strange results */
- if ((mb->thresh > 0.2f) && (f == 1)) {
- if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0] - negative * dvec[0] / (positive - negative);
- p[1] = neg[1];
- p[2] = neg[2];
- return;
- }
- if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1] - negative * dvec[1] / (positive - negative);
- p[2] = neg[2];
- return;
- }
- if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1];
- p[2] = neg[2] - negative * dvec[2] / (positive - negative);
- return;
- }
- }
-
- if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) {
- p[1] = neg[1];
- p[2] = neg[2];
- while (1) {
- if (i++ == RES) return;
- p[0] = 0.5f * (pos[0] + neg[0]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[0] = p[0];
- else neg[0] = p[0];
- }
- }
-
- if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0];
- p[2] = neg[2];
- while (1) {
- if (i++ == RES) return;
- p[1] = 0.5f * (pos[1] + neg[1]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[1] = p[1];
- else neg[1] = p[1];
- }
- }
-
- if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1];
- while (1) {
- if (i++ == RES) return;
- p[2] = 0.5f * (pos[2] + neg[2]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[2] = p[2];
- else neg[2] = p[2];
- }
- }
-
- /* This is necessary to find start point */
- while (1) {
- mid_v3_v3v3(&p[0], pos, neg);
-
- if (i++ == RES) {
- return;
- }
-
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) {
- copy_v3_v3(pos, &p[0]);
- }
- else {
- copy_v3_v3(neg, &p[0]);
- }
- }
-}
-
-/* ************************************** */
-static void add_cube(PROCESS *process, int i, int j, int k, int count)
-{
- CUBES *ncube;
- int n;
- int a, b, c;
-
- /* hmmm, not only one, but eight cube will be added on the stack
- * ... */
- for (a = i - 1; a < i + count; a++)
- for (b = j - 1; b < j + count; b++)
- for (c = k - 1; c < k + count; c++) {
- /* test if cube has been found before */
- if (setcenter(process, process->centers, a, b, c) == 0) {
- /* push cube on stack: */
- ncube = (CUBES *) new_pgn_element(process, sizeof(CUBES));
- ncube->next = process->cubes;
- process->cubes = ncube;
-
- ncube->cube.i = a;
- ncube->cube.j = b;
- ncube->cube.k = c;
-
- /* set corners of initial cube: */
- for (n = 0; n < 8; n++)
- ncube->cube.corners[n] = setcorner(process, a + MB_BIT(n, 2), b + MB_BIT(n, 1), c + MB_BIT(n, 0));
- }
- }
-}
-
-
-static void find_first_points(PROCESS *process, MetaBall *mb, int a)
-{
- MetaElem *ml;
- float f;
-
- ml = process->mainb[a];
- f = 1.0f - (mb->thresh / ml->s);
-
- /* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be
- * visible alone ... but still can influence others MetaElements :-) */
- if (f > 0.0f) {
- float IN[3] = {0.0f}, OUT[3] = {0.0f}, in[3] = {0.0f}, out[3];
- int i, j, k, c_i, c_j, c_k;
- int index[3] = {1, 0, -1};
- float in_v /*, out_v*/;
- float workp[3];
- float dvec[3];
- float tmp_v, workp_v, max_len_sq, nx, ny, nz, max_dim;
-
- calc_mballco(ml, in);
- in_v = process->function(process, in[0], in[1], in[2]);
-
- for (i = 0; i < 3; i++) {
- switch (ml->type) {
- case MB_BALL:
- OUT[0] = out[0] = IN[0] + index[i] * ml->rad;
- break;
- case MB_TUBE:
- case MB_PLANE:
- case MB_ELIPSOID:
- case MB_CUBE:
- OUT[0] = out[0] = IN[0] + index[i] * (ml->expx + ml->rad);
- break;
- }
-
- for (j = 0; j < 3; j++) {
- switch (ml->type) {
- case MB_BALL:
- OUT[1] = out[1] = IN[1] + index[j] * ml->rad;
- break;
- case MB_TUBE:
- case MB_PLANE:
- case MB_ELIPSOID:
- case MB_CUBE:
- OUT[1] = out[1] = IN[1] + index[j] * (ml->expy + ml->rad);
- break;
- }
-
- for (k = 0; k < 3; k++) {
- out[0] = OUT[0];
- out[1] = OUT[1];
- switch (ml->type) {
- case MB_BALL:
- case MB_TUBE:
- case MB_PLANE:
- out[2] = IN[2] + index[k] * ml->rad;
- break;
- case MB_ELIPSOID:
- case MB_CUBE:
- out[2] = IN[2] + index[k] * (ml->expz + ml->rad);
- break;
- }
-
- calc_mballco(ml, out);
-
- /*out_v = process->function(out[0], out[1], out[2]);*/ /*UNUSED*/
-
- /* find "first points" on Implicit Surface of MetaElemnt ml */
- copy_v3_v3(workp, in);
- workp_v = in_v;
- max_len_sq = len_squared_v3v3(out, in);
-
- nx = fabsf((out[0] - in[0]) / process->size);
- ny = fabsf((out[1] - in[1]) / process->size);
- nz = fabsf((out[2] - in[2]) / process->size);
-
- max_dim = max_fff(nx, ny, nz);
- if (max_dim != 0.0f) {
- float len_sq = 0.0f;
-
- dvec[0] = (out[0] - in[0]) / max_dim;
- dvec[1] = (out[1] - in[1]) / max_dim;
- dvec[2] = (out[2] - in[2]) / max_dim;
-
- while (len_sq <= max_len_sq) {
- add_v3_v3(workp, dvec);
-
- /* compute value of implicite function */
- tmp_v = process->function(process, workp[0], workp[1], workp[2]);
- /* add cube to the stack, when value of implicite function crosses zero value */
- if ((tmp_v < 0.0f && workp_v >= 0.0f) || (tmp_v > 0.0f && workp_v <= 0.0f)) {
-
- /* indexes of CUBE, which includes "first point" */
- c_i = (int)floor(workp[0] / process->size);
- c_j = (int)floor(workp[1] / process->size);
- c_k = (int)floor(workp[2] / process->size);
-
- /* add CUBE (with indexes c_i, c_j, c_k) to the stack,
- * this cube includes found point of Implicit Surface */
- if ((ml->flag & MB_NEGATIVE) == 0) {
- add_cube(process, c_i, c_j, c_k, 1);
- }
- else {
- add_cube(process, c_i, c_j, c_k, 2);
- }
- }
- len_sq = len_squared_v3v3(workp, in);
- workp_v = tmp_v;
-
- }
- }
- }
- }
- }
- }
-}
-
-static void polygonize(PROCESS *process, MetaBall *mb)
-{
- CUBE c;
- int a;
-
- process->vertices.count = process->vertices.max = 0;
- process->vertices.ptr = NULL;
-
- /* allocate hash tables and build cube polygon table: */
- process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
- process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
- process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
- makecubetable();
-
- for (a = 0; a < process->totelem; a++) {
-
- /* try to find 8 points on the surface for each MetaElem */
- find_first_points(process, mb, a);
- }
-
- /* polygonize all MetaElems of current MetaBall */
- while (process->cubes != NULL) { /* process active cubes till none left */
- c = process->cubes->cube;
-
- /* polygonize the cube directly: */
- docube(process, &c, mb);
-
- /* pop current cube from stack */
- process->cubes = process->cubes->next;
-
- /* test six face directions, maybe add to stack: */
- testface(process, c.i - 1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF);
- testface(process, c.i + 1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF);
- testface(process, c.i, c.j - 1, c.k, &c, 1, LBN, LBF, RBN, RBF);
- testface(process, c.i, c.j + 1, c.k, &c, 1, LTN, LTF, RTN, RTF);
- testface(process, c.i, c.j, c.k - 1, &c, 0, LBN, LTN, RBN, RTN);
- testface(process, c.i, c.j, c.k + 1, &c, 0, LBF, LTF, RBF, RTF);
- }
-}
-
-static float init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) /* return totsize */
-{
- Scene *sce_iter = scene;
- Base *base;
- Object *bob;
- MetaBall *mb;
- MetaElem *ml;
- float size, totsize, obinv[4][4], obmat[4][4], vec[3];
- //float max = 0.0f;
- int a, obnr, zero_size = 0;
- char obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
- invert_m4_m4(obinv, ob->obmat);
- a = 0;
-
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* make main array */
- BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
-
- if (bob->type == OB_MBALL) {
- zero_size = 0;
- ml = NULL;
-
- if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
- mb = ob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- else {
- char name[MAX_ID_NAME];
- int nr;
-
- BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
- if (STREQ(obname, name)) {
- mb = bob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- }
-
- /* when metaball object has zero scale, then MetaElem to this MetaBall
- * will not be put to mainb array */
- if (has_zero_axis_m4(bob->obmat)) {
- zero_size = 1;
- }
- else if (bob->parent) {
- struct Object *pob = bob->parent;
- while (pob) {
- if (has_zero_axis_m4(pob->obmat)) {
- zero_size = 1;
- break;
- }
- pob = pob->parent;
- }
- }
-
- if (zero_size) {
- unsigned int ml_count = 0;
- while (ml) {
- ml_count++;
- ml = ml->next;
- }
- process->totelem -= ml_count;
- }
- else {
- while (ml) {
- if (!(ml->flag & MB_HIDE)) {
- int i;
- float temp1[4][4], temp2[4][4], temp3[4][4];
- float (*mat)[4] = NULL, (*imat)[4] = NULL;
- float max_x, max_y, max_z, min_x, min_y, min_z;
- float expx, expy, expz;
-
- max_x = max_y = max_z = -3.4e38;
- min_x = min_y = min_z = 3.4e38;
-
- /* too big stiffness seems only ugly due to linear interpolation
- * no need to have possibility for too big stiffness */
- if (ml->s > 10.0f) ml->s = 10.0f;
-
- /* Rotation of MetaElem is stored in quat */
- quat_to_mat4(temp3, ml->quat);
-
- /* Translation of MetaElem */
- unit_m4(temp2);
- temp2[3][0] = ml->x;
- temp2[3][1] = ml->y;
- temp2[3][2] = ml->z;
-
- mul_m4_m4m4(temp1, temp2, temp3);
-
- /* make a copy because of duplicates */
- process->mainb[a] = new_pgn_element(process, sizeof(MetaElem));
- *(process->mainb[a]) = *ml;
- process->mainb[a]->bb = new_pgn_element(process, sizeof(BoundBox));
-
- mat = new_pgn_element(process, 4 * 4 * sizeof(float));
- imat = new_pgn_element(process, 4 * 4 * sizeof(float));
-
- /* mat is the matrix to transform from mball into the basis-mball */
- invert_m4_m4(obinv, obmat);
- mul_m4_m4m4(temp2, obinv, bob->obmat);
- /* MetaBall transformation */
- mul_m4_m4m4(mat, temp2, temp1);
-
- invert_m4_m4(imat, mat);
-
- process->mainb[a]->rad2 = ml->rad * ml->rad;
-
- process->mainb[a]->mat = (float *) mat;
- process->mainb[a]->imat = (float *) imat;
-
- if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
- expx = ml->expx;
- expy = ml->expy;
- expz = ml->expz;
- }
- else {
- expx = ml->expx * ml->expx;
- expy = ml->expy * ml->expy;
- expz = ml->expz * ml->expz;
- }
-
- /* untransformed Bounding Box of MetaElem */
- /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
- copy_v3_fl3(process->mainb[a]->bb->vec[0], -expx, -expy, -expz); /* 0 */
- copy_v3_fl3(process->mainb[a]->bb->vec[1], +expx, -expy, -expz); /* 1 */
- copy_v3_fl3(process->mainb[a]->bb->vec[2], +expx, +expy, -expz); /* 2 */
- copy_v3_fl3(process->mainb[a]->bb->vec[3], -expx, +expy, -expz); /* 3 */
- copy_v3_fl3(process->mainb[a]->bb->vec[4], -expx, -expy, +expz); /* 4 */
- copy_v3_fl3(process->mainb[a]->bb->vec[5], +expx, -expy, +expz); /* 5 */
- copy_v3_fl3(process->mainb[a]->bb->vec[6], +expx, +expy, +expz); /* 6 */
- copy_v3_fl3(process->mainb[a]->bb->vec[7], -expx, +expy, +expz); /* 7 */
-
- /* transformation of Metalem bb */
- for (i = 0; i < 8; i++)
- mul_m4_v3((float (*)[4])mat, process->mainb[a]->bb->vec[i]);
-
- /* find max and min of transformed bb */
- for (i = 0; i < 8; i++) {
- /* find maximums */
- if (process->mainb[a]->bb->vec[i][0] > max_x) max_x = process->mainb[a]->bb->vec[i][0];
- if (process->mainb[a]->bb->vec[i][1] > max_y) max_y = process->mainb[a]->bb->vec[i][1];
- if (process->mainb[a]->bb->vec[i][2] > max_z) max_z = process->mainb[a]->bb->vec[i][2];
- /* find minimums */
- if (process->mainb[a]->bb->vec[i][0] < min_x) min_x = process->mainb[a]->bb->vec[i][0];
- if (process->mainb[a]->bb->vec[i][1] < min_y) min_y = process->mainb[a]->bb->vec[i][1];
- if (process->mainb[a]->bb->vec[i][2] < min_z) min_z = process->mainb[a]->bb->vec[i][2];
- }
-
- /* create "new" bb, only point 0 and 6, which are
- * necessary for octal tree filling */
- process->mainb[a]->bb->vec[0][0] = min_x - ml->rad;
- process->mainb[a]->bb->vec[0][1] = min_y - ml->rad;
- process->mainb[a]->bb->vec[0][2] = min_z - ml->rad;
-
- process->mainb[a]->bb->vec[6][0] = max_x + ml->rad;
- process->mainb[a]->bb->vec[6][1] = max_y + ml->rad;
- process->mainb[a]->bb->vec[6][2] = max_z + ml->rad;
-
- a++;
- }
- ml = ml->next;
- }
- }
- }
- }
-
-
- /* totsize (= 'manhattan' radius) */
- totsize = 0.0;
- for (a = 0; a < process->totelem; a++) {
-
- vec[0] = process->mainb[a]->x + process->mainb[a]->rad + process->mainb[a]->expx;
- vec[1] = process->mainb[a]->y + process->mainb[a]->rad + process->mainb[a]->expy;
- vec[2] = process->mainb[a]->z + process->mainb[a]->rad + process->mainb[a]->expz;
-
- calc_mballco(process->mainb[a], vec);
-
- size = fabsf(vec[0]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[1]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[2]);
- if (size > totsize) totsize = size;
-
- vec[0] = process->mainb[a]->x - process->mainb[a]->rad;
- vec[1] = process->mainb[a]->y - process->mainb[a]->rad;
- vec[2] = process->mainb[a]->z - process->mainb[a]->rad;
-
- calc_mballco(process->mainb[a], vec);
-
- size = fabsf(vec[0]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[1]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[2]);
- if (size > totsize) totsize = size;
- }
-
- for (a = 0; a < process->totelem; a++) {
- process->thresh += densfunc(process->mainb[a], 2.0f * totsize, 2.0f * totsize, 2.0f * totsize);
- }
-
- return totsize;
-}
-
-/* if MetaElem lies in node, then node includes MetaElem pointer (ml_p)
- * pointing at MetaElem (ml)
- */
-static void fill_metaball_octal_node(octal_node *node, MetaElem *ml, short i)
-{
- ml_pointer *ml_p;
-
- ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
- ml_p->ml = ml;
- BLI_addtail(&(node->nodes[i]->elems), ml_p);
- node->count++;
-
- if ((ml->flag & MB_NEGATIVE) == 0) {
- node->nodes[i]->pos++;
- }
- else {
- node->nodes[i]->neg++;
- }
-}
-
-/* Node is subdivided as is illustrated on the following figure:
- *
- * +------+------+
- * / / /|
- * +------+------+ |
- * / / /| +
- * +------+------+ |/|
- * | | | + |
- * | | |/| +
- * +------+------+ |/
- * | | | +
- * | | |/
- * +------+------+
- *
- */
-static void subdivide_metaball_octal_node(octal_node *node, float size_x, float size_y, float size_z, short depth)
-{
- MetaElem *ml;
- ml_pointer *ml_p;
- float x, y, z;
- int a, i;
-
- /* create new nodes */
- for (a = 0; a < 8; a++) {
- node->nodes[a] = MEM_mallocN(sizeof(octal_node), "octal_node");
- for (i = 0; i < 8; i++)
- node->nodes[a]->nodes[i] = NULL;
- node->nodes[a]->parent = node;
- BLI_listbase_clear(&node->nodes[a]->elems);
- node->nodes[a]->count = 0;
- node->nodes[a]->neg = 0;
- node->nodes[a]->pos = 0;
- }
-
- size_x /= 2;
- size_y /= 2;
- size_z /= 2;
-
- /* center of node */
- node->x = x = node->x_min + size_x;
- node->y = y = node->y_min + size_y;
- node->z = z = node->z_min + size_z;
-
- /* setting up of border points of new nodes */
- node->nodes[0]->x_min = node->x_min;
- node->nodes[0]->y_min = node->y_min;
- node->nodes[0]->z_min = node->z_min;
- node->nodes[0]->x = node->nodes[0]->x_min + size_x / 2;
- node->nodes[0]->y = node->nodes[0]->y_min + size_y / 2;
- node->nodes[0]->z = node->nodes[0]->z_min + size_z / 2;
-
- node->nodes[1]->x_min = x;
- node->nodes[1]->y_min = node->y_min;
- node->nodes[1]->z_min = node->z_min;
- node->nodes[1]->x = node->nodes[1]->x_min + size_x / 2;
- node->nodes[1]->y = node->nodes[1]->y_min + size_y / 2;
- node->nodes[1]->z = node->nodes[1]->z_min + size_z / 2;
-
- node->nodes[2]->x_min = x;
- node->nodes[2]->y_min = y;
- node->nodes[2]->z_min = node->z_min;
- node->nodes[2]->x = node->nodes[2]->x_min + size_x / 2;
- node->nodes[2]->y = node->nodes[2]->y_min + size_y / 2;
- node->nodes[2]->z = node->nodes[2]->z_min + size_z / 2;
-
- node->nodes[3]->x_min = node->x_min;
- node->nodes[3]->y_min = y;
- node->nodes[3]->z_min = node->z_min;
- node->nodes[3]->x = node->nodes[3]->x_min + size_x / 2;
- node->nodes[3]->y = node->nodes[3]->y_min + size_y / 2;
- node->nodes[3]->z = node->nodes[3]->z_min + size_z / 2;
-
- node->nodes[4]->x_min = node->x_min;
- node->nodes[4]->y_min = node->y_min;
- node->nodes[4]->z_min = z;
- node->nodes[4]->x = node->nodes[4]->x_min + size_x / 2;
- node->nodes[4]->y = node->nodes[4]->y_min + size_y / 2;
- node->nodes[4]->z = node->nodes[4]->z_min + size_z / 2;
-
- node->nodes[5]->x_min = x;
- node->nodes[5]->y_min = node->y_min;
- node->nodes[5]->z_min = z;
- node->nodes[5]->x = node->nodes[5]->x_min + size_x / 2;
- node->nodes[5]->y = node->nodes[5]->y_min + size_y / 2;
- node->nodes[5]->z = node->nodes[5]->z_min + size_z / 2;
-
- node->nodes[6]->x_min = x;
- node->nodes[6]->y_min = y;
- node->nodes[6]->z_min = z;
- node->nodes[6]->x = node->nodes[6]->x_min + size_x / 2;
- node->nodes[6]->y = node->nodes[6]->y_min + size_y / 2;
- node->nodes[6]->z = node->nodes[6]->z_min + size_z / 2;
-
- node->nodes[7]->x_min = node->x_min;
- node->nodes[7]->y_min = y;
- node->nodes[7]->z_min = z;
- node->nodes[7]->x = node->nodes[7]->x_min + size_x / 2;
- node->nodes[7]->y = node->nodes[7]->y_min + size_y / 2;
- node->nodes[7]->z = node->nodes[7]->z_min + size_z / 2;
-
- ml_p = node->elems.first;
-
- /* setting up references of MetaElems for new nodes */
- while (ml_p) {
- ml = ml_p->ml;
- if (ml->bb->vec[0][2] < z) {
- if (ml->bb->vec[0][1] < y) {
- /* vec[0][0] lies in first octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (0)1st node */
- fill_metaball_octal_node(node, ml, 0);
-
- /* ml belongs to the (3)4th node */
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 3);
-
- /* ml belongs to the (7)8th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 7);
- }
- }
-
- /* ml belongs to the (1)2nd node */
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 1);
-
- /* ml belongs to the (5)6th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 5);
- }
- }
-
- /* ml belongs to the (2)3th node */
- if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belong to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
-
- }
-
- /* ml belongs to the (4)5th node too */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 4);
- }
-
-
-
- }
- /* vec[0][0] is in the (1)second octant */
- else {
- /* ml belong to the (1)2nd node */
- fill_metaball_octal_node(node, ml, 1);
-
- /* ml belongs to the (2)3th node */
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
-
- }
-
- /* ml belongs to the (5)6th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 5);
- }
- }
- }
- else {
- /* vec[0][0] is in the (3)4th octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (3)4nd node */
- fill_metaball_octal_node(node, ml, 3);
-
- /* ml belongs to the (7)8th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 7);
- }
-
-
- /* ml belongs to the (2)3th node */
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
-
- }
-
- /* vec[0][0] is in the (2)3th octant */
- if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) {
- /* ml belongs to the (2)3th node */
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
- else {
- if (ml->bb->vec[0][1] < y) {
- /* vec[0][0] lies in (4)5th octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (4)5th node */
- fill_metaball_octal_node(node, ml, 4);
-
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 5);
- }
-
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 7);
- }
-
- if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- /* vec[0][0] lies in (5)6th octant */
- else {
- fill_metaball_octal_node(node, ml, 5);
-
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
- else {
- /* vec[0][0] lies in (7)8th octant */
- if (ml->bb->vec[0][0] < x) {
- fill_metaball_octal_node(node, ml, 7);
-
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
-
- }
-
- /* vec[0][0] lies in (6)7th octant */
- if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- ml_p = ml_p->next;
- }
-
- /* free references of MetaElems for curent node (it is not needed anymore) */
- BLI_freelistN(&node->elems);
-
- depth--;
-
- if (depth > 0) {
- for (a = 0; a < 8; a++) {
- if (node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */
- subdivide_metaball_octal_node(node->nodes[a], size_x, size_y, size_z, depth);
- }
- }
-}
-
-/* free all octal nodes recursively */
-static void free_metaball_octal_node(octal_node *node)
-{
- int a;
- for (a = 0; a < 8; a++) {
- if (node->nodes[a] != NULL) free_metaball_octal_node(node->nodes[a]);
- }
- BLI_freelistN(&node->elems);
- MEM_freeN(node);
-}
-
-/* If scene include more than one MetaElem, then octree is used */
-static void init_metaball_octal_tree(PROCESS *process, int depth)
-{
- struct octal_node *node;
- ml_pointer *ml_p;
- float size[3];
- int a;
-
- process->metaball_tree = MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree");
- process->metaball_tree->first = node = MEM_mallocN(sizeof(octal_node), "metaball_octal_node");
- /* maximal depth of octree */
- process->metaball_tree->depth = depth;
-
- process->metaball_tree->neg = node->neg = 0;
- process->metaball_tree->pos = node->pos = 0;
-
- BLI_listbase_clear(&node->elems);
- node->count = 0;
-
- for (a = 0; a < 8; a++)
- node->nodes[a] = NULL;
-
- node->x_min = node->y_min = node->z_min = FLT_MAX;
- node->x_max = node->y_max = node->z_max = -FLT_MAX;
-
- /* size of octal tree scene */
- for (a = 0; a < process->totelem; a++) {
- if (process->mainb[a]->bb->vec[0][0] < node->x_min) node->x_min = process->mainb[a]->bb->vec[0][0];
- if (process->mainb[a]->bb->vec[0][1] < node->y_min) node->y_min = process->mainb[a]->bb->vec[0][1];
- if (process->mainb[a]->bb->vec[0][2] < node->z_min) node->z_min = process->mainb[a]->bb->vec[0][2];
-
- if (process->mainb[a]->bb->vec[6][0] > node->x_max) node->x_max = process->mainb[a]->bb->vec[6][0];
- if (process->mainb[a]->bb->vec[6][1] > node->y_max) node->y_max = process->mainb[a]->bb->vec[6][1];
- if (process->mainb[a]->bb->vec[6][2] > node->z_max) node->z_max = process->mainb[a]->bb->vec[6][2];
-
- ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
- ml_p->ml = process->mainb[a];
- BLI_addtail(&node->elems, ml_p);
-
- if ((process->mainb[a]->flag & MB_NEGATIVE) == 0) {
- /* number of positive MetaElem in scene */
- process->metaball_tree->pos++;
- }
- else {
- /* number of negative MetaElem in scene */
- process->metaball_tree->neg++;
- }
- }
-
- /* size of first node */
- size[0] = node->x_max - node->x_min;
- size[1] = node->y_max - node->y_min;
- size[2] = node->z_max - node->z_min;
-
- /* first node is subdivided recursively */
- subdivide_metaball_octal_node(node, size[0], size[1], size[2], process->metaball_tree->depth);
-}
-
-static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *basis)
-{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob, *bob = basis;
- MetaElem *ml = NULL;
- int basisnr, obnr;
- char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- process->totelem = 0;
-
- BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
- if (ob->type == OB_MBALL) {
- if (ob == bob) {
- MetaBall *mb = ob->data;
-
- /* if bob object is in edit mode, then dynamic list of all MetaElems
- * is stored in editelems */
- if (mb->editelems) ml = mb->editelems->first;
- /* if bob object is in object mode */
- else ml = mb->elems.first;
- }
- else {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* object ob has to be in same "group" ... it means, that it has to have
- * same base of its name */
- if (STREQ(obname, basisname)) {
- MetaBall *mb = ob->data;
-
- /* if object is in edit mode, then dynamic list of all MetaElems
- * is stored in editelems */
- if (mb->editelems) ml = mb->editelems->first;
- /* if bob object is in object mode */
- else ml = mb->elems.first;
- }
- }
-
- for ( ; ml; ml = ml->next) {
- if (!(ml->flag & MB_HIDE)) {
- process->totelem++;
- }
- }
- }
- }
-}
-
-void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
-{
- MetaBall *mb;
- DispList *dl;
- int a, nr_cubes;
- float *co, *no, totsize, width;
- PROCESS process = {0};
-
- mb = ob->data;
-
- mball_count(eval_ctx, &process, scene, ob);
-
- if (process.totelem == 0) return;
- if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
-
- process.thresh = mb->thresh;
-
- /* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */
- process.mainb = MEM_mallocN(sizeof(void *) * process.totelem, "mainb");
-
- /* initialize all mainb (MetaElems) */
- totsize = init_meta(eval_ctx, &process, scene, ob);
-
- /* if scene includes more than one MetaElem, then octal tree optimization is used */
- if ((process.totelem > 1) && (process.totelem <= 64)) init_metaball_octal_tree(&process, 1);
- if ((process.totelem > 64) && (process.totelem <= 128)) init_metaball_octal_tree(&process, 2);
- if ((process.totelem > 128) && (process.totelem <= 512)) init_metaball_octal_tree(&process, 3);
- if ((process.totelem > 512) && (process.totelem <= 1024)) init_metaball_octal_tree(&process, 4);
- if (process.totelem > 1024) init_metaball_octal_tree(&process, 5);
-
- /* don't polygonize metaballs with too high resolution (base mball to small)
- * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
- if (process.metaball_tree) {
- if (ob->size[0] <= 0.00001f * (process.metaball_tree->first->x_max - process.metaball_tree->first->x_min) ||
- ob->size[1] <= 0.00001f * (process.metaball_tree->first->y_max - process.metaball_tree->first->y_min) ||
- ob->size[2] <= 0.00001f * (process.metaball_tree->first->z_max - process.metaball_tree->first->z_min))
- {
- new_pgn_element(&process, -1); /* free values created by init_meta */
-
- MEM_freeN(process.mainb);
-
- /* free tree */
- free_metaball_octal_node(process.metaball_tree->first);
- MEM_freeN(process.metaball_tree);
-
- return;
- }
- }
-
- /* width is size per polygonize cube */
- if (eval_ctx->mode == DAG_EVAL_RENDER) {
- width = mb->rendersize;
- }
- else {
- width = mb->wiresize;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
- width *= 2;
- }
- }
- /* nr_cubes is just for safety, minimum is totsize */
- nr_cubes = (int)(0.5f + totsize / width);
-
- /* init process */
- process.function = metaball;
- process.size = width;
- process.bounds = nr_cubes;
- process.cubes = NULL;
- process.delta = width / (float)(RES * RES);
-
- polygonize(&process, mb);
-
- MEM_freeN(process.mainb);
-
- /* free octal tree */
- if (process.totelem > 1) {
- free_metaball_octal_node(process.metaball_tree->first);
- MEM_freeN(process.metaball_tree);
- process.metaball_tree = NULL;
- }
-
- if (process.curindex) {
- VERTEX *ptr = process.vertices.ptr;
-
- dl = MEM_callocN(sizeof(DispList), "mbaldisp");
- BLI_addtail(dispbase, dl);
- dl->type = DL_INDEX4;
- dl->nr = process.vertices.count;
- dl->parts = process.curindex;
-
- dl->index = process.indices;
- process.indices = NULL;
-
- a = process.vertices.count;
- dl->verts = co = MEM_mallocN(sizeof(float[3]) * a, "mballverts");
- dl->nors = no = MEM_mallocN(sizeof(float[3]) * a, "mballnors");
-
- for (a = 0; a < process.vertices.count; ptr++, a++, no += 3, co += 3) {
- copy_v3_v3(co, ptr->co);
- copy_v3_v3(no, ptr->no);
- }
- }
-
- freepolygonize(&process);
-}
-
bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
float obmat[4][4], const short flag)
{
@@ -2511,3 +586,9 @@ void BKE_mball_select_swap(struct MetaBall *mb)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ MetaBall *UNUSED(mball))
+{
+}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
new file mode 100644
index 00000000000..e8418e876bb
--- /dev/null
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -0,0 +1,1325 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mball_tessellate.c
+ * \ingroup bke
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_memarena.h"
+
+#include "BKE_global.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+#include "BKE_displist.h"
+#include "BKE_mball_tessellate.h" /* own include */
+
+#include "BLI_strict_flags.h"
+
+/* experimental (faster) normal calculation */
+// #define USE_ACCUM_NORMAL
+
+/* Data types */
+
+typedef struct corner { /* corner of a cube */
+ int i, j, k; /* (i, j, k) is index within lattice */
+ float co[3], value; /* location and function value */
+ struct corner *next;
+} CORNER;
+
+typedef struct cube { /* partitioning cell (cube) */
+ int i, j, k; /* lattice location of cube */
+ CORNER *corners[8]; /* eight corners */
+} CUBE;
+
+typedef struct cubes { /* linked list of cubes acting as stack */
+ CUBE cube; /* a single cube */
+ struct cubes *next; /* remaining elements */
+} CUBES;
+
+typedef struct centerlist { /* list of cube locations */
+ int i, j, k; /* cube location */
+ struct centerlist *next; /* remaining elements */
+} CENTERLIST;
+
+typedef struct edgelist { /* list of edges */
+ int i1, j1, k1, i2, j2, k2; /* edge corner ids */
+ int vid; /* vertex id */
+ struct edgelist *next; /* remaining elements */
+} EDGELIST;
+
+typedef struct intlist { /* list of integers */
+ int i; /* an integer */
+ struct intlist *next; /* remaining elements */
+} INTLIST;
+
+typedef struct intlists { /* list of list of integers */
+ INTLIST *list; /* a list of integers */
+ struct intlists *next; /* remaining elements */
+} INTLISTS;
+
+typedef struct Box { /* an AABB with pointer to metalelem */
+ float min[3], max[3];
+ const MetaElem *ml;
+} Box;
+
+typedef struct MetaballBVHNode { /* BVH node */
+ Box bb[2]; /* AABB of children */
+ struct MetaballBVHNode *child[2];
+} MetaballBVHNode;
+
+typedef struct process { /* parameters, storage */
+ float thresh, size; /* mball threshold, single cube size */
+ float delta; /* small delta for calculating normals */
+ unsigned int converge_res; /* converge procedure resolution (more = slower) */
+
+ MetaElem **mainb; /* array of all metaelems */
+ unsigned int totelem, mem; /* number of metaelems */
+
+ MetaballBVHNode metaball_bvh; /* The simplest bvh */
+ Box allbb; /* Bounding box of all metaelems */
+
+ MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */
+ unsigned int bvh_queue_size;
+
+ CUBES *cubes; /* stack of cubes waiting for polygonization */
+ CENTERLIST **centers; /* cube center hash table */
+ CORNER **corners; /* corner value hash table */
+ EDGELIST **edges; /* edge and vertex id hash table */
+
+ int (*indices)[4]; /* output indices */
+ unsigned int totindex; /* size of memory allocated for indices */
+ unsigned int curindex; /* number of currently added indices */
+
+ float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */
+ unsigned int totvertex; /* memory size */
+ unsigned int curvertex; /* currently added vertices */
+
+ /* memory allocation from common pool */
+ MemArena *pgn_elements;
+} PROCESS;
+
+/* Forward declarations */
+static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2);
+static void add_cube(PROCESS *process, int i, int j, int k);
+static void make_face(PROCESS *process, int i1, int i2, int i3, int i4);
+static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]);
+
+/* ******************* SIMPLE BVH ********************* */
+
+static void make_box_union(const BoundBox *a, const Box *b, Box *r_out)
+{
+ r_out->min[0] = min_ff(a->vec[0][0], b->min[0]);
+ r_out->min[1] = min_ff(a->vec[0][1], b->min[1]);
+ r_out->min[2] = min_ff(a->vec[0][2], b->min[2]);
+
+ r_out->max[0] = max_ff(a->vec[6][0], b->max[0]);
+ r_out->max[1] = max_ff(a->vec[6][1], b->max[1]);
+ r_out->max[2] = max_ff(a->vec[6][2], b->max[2]);
+}
+
+static void make_box_from_metaelem(Box *r, const MetaElem *ml)
+{
+ copy_v3_v3(r->max, ml->bb->vec[6]);
+ copy_v3_v3(r->min, ml->bb->vec[0]);
+ r->ml = ml;
+}
+
+/**
+ * Partitions part of mainb array [start, end) along axis s. Returns i,
+ * where centroids of elements in the [start, i) segment lie "on the right side" of div,
+ * and elements in the [i, end) segment lie "on the left"
+ */
+static unsigned int partition_mainb(MetaElem **mainb, unsigned int start, unsigned int end, unsigned int s, float div)
+{
+ unsigned int i = start, j = end - 1;
+ div *= 2.0f;
+
+ while (1) {
+ while (i < j && div > (mainb[i]->bb->vec[6][s] + mainb[i]->bb->vec[0][s])) i++;
+ while (j > i && div < (mainb[j]->bb->vec[6][s] + mainb[j]->bb->vec[0][s])) j--;
+
+ if (i >= j)
+ break;
+
+ SWAP(MetaElem *, mainb[i], mainb[j]);
+ i++;
+ j--;
+ }
+
+ if (i == start) {
+ i++;
+ }
+
+ return i;
+}
+
+/**
+ * Recursively builds a BVH, dividing elements along the middle of the longest axis of allbox.
+ */
+static void build_bvh_spatial(
+ PROCESS *process, MetaballBVHNode *node,
+ unsigned int start, unsigned int end, const Box *allbox)
+{
+ unsigned int part, j, s;
+ float dim[3], div;
+
+ /* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */
+ process->bvh_queue_size++;
+
+ dim[0] = allbox->max[0] - allbox->min[0];
+ dim[1] = allbox->max[1] - allbox->min[1];
+ dim[2] = allbox->max[2] - allbox->min[2];
+
+ s = 0;
+ if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1;
+ else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2;
+
+ div = allbox->min[s] + (dim[s] / 2.0f);
+
+ part = partition_mainb(process->mainb, start, end, s, div);
+
+ make_box_from_metaelem(&node->bb[0], process->mainb[start]);
+ node->child[0] = NULL;
+
+ if (part > start + 1) {
+ for (j = start; j < part; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]);
+ }
+
+ node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]);
+ }
+
+ node->child[1] = NULL;
+ if (part < end) {
+ make_box_from_metaelem(&node->bb[1], process->mainb[part]);
+
+ if (part < end - 1) {
+ for (j = part; j < end; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]);
+ }
+
+ node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]);
+ }
+ }
+ else {
+ INIT_MINMAX(node->bb[1].min, node->bb[1].max);
+ }
+}
+
+/* ******************** ARITH ************************* */
+
+/**
+ * BASED AT CODE (but mostly rewritten) :
+ * C code from the article
+ * "An Implicit Surface Polygonizer"
+ * by Jules Bloomenthal, jbloom@beauty.gmu.edu
+ * in "Graphics Gems IV", Academic Press, 1994
+ *
+ * Authored by Jules Bloomenthal, Xerox PARC.
+ * Copyright (c) Xerox Corporation, 1991. All rights reserved.
+ * Permission is granted to reproduce, use and distribute this code for
+ * any and all purposes, provided that this notice appears in all copies.
+ */
+
+#define L 0 /* left direction: -x, -i */
+#define R 1 /* right direction: +x, +i */
+#define B 2 /* bottom direction: -y, -j */
+#define T 3 /* top direction: +y, +j */
+#define N 4 /* near direction: -z, -k */
+#define F 5 /* far direction: +z, +k */
+#define LBN 0 /* left bottom near corner */
+#define LBF 1 /* left bottom far corner */
+#define LTN 2 /* left top near corner */
+#define LTF 3 /* left top far corner */
+#define RBN 4 /* right bottom near corner */
+#define RBF 5 /* right bottom far corner */
+#define RTN 6 /* right top near corner */
+#define RTF 7 /* right top far corner */
+
+/**
+ * the LBN corner of cube (i, j, k), corresponds with location
+ * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size)
+ */
+
+#define HASHBIT (5)
+#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
+
+#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) )
+
+#define MB_BIT(i, bit) (((i) >> (bit)) & 1)
+// #define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */
+
+/* ******************** DENSITY COPMPUTATION ********************* */
+
+/**
+ * Computes density from given metaball at given position.
+ * Metaball equation is: ``(1 - r^2 / R^2)^3 * s``
+ *
+ * r = distance from center
+ * R = metaball radius
+ * s - metaball stiffness
+ */
+static float densfunc(const MetaElem *ball, float x, float y, float z)
+{
+ float dist2;
+ float dvec[3] = {x, y, z};
+
+ mul_m4_v3((float (*)[4])ball->imat, dvec);
+
+ switch (ball->type) {
+ case MB_BALL:
+ /* do nothing */
+ break;
+ case MB_CUBE:
+ 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 */
+ 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 */
+ case MB_TUBE:
+ if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
+ else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
+ else dvec[0] = 0.0;
+ break;
+ case MB_ELIPSOID:
+ dvec[0] /= ball->expx;
+ dvec[1] /= ball->expy;
+ dvec[2] /= ball->expz;
+ break;
+
+ /* *** deprecated, could be removed?, do-versioned at least *** */
+ case MB_TUBEX:
+ if (dvec[0] > ball->len) dvec[0] -= ball->len;
+ else if (dvec[0] < -ball->len) dvec[0] += ball->len;
+ else dvec[0] = 0.0;
+ break;
+ case MB_TUBEY:
+ if (dvec[1] > ball->len) dvec[1] -= ball->len;
+ else if (dvec[1] < -ball->len) dvec[1] += ball->len;
+ else dvec[1] = 0.0;
+ break;
+ case MB_TUBEZ:
+ if (dvec[2] > ball->len) dvec[2] -= ball->len;
+ else if (dvec[2] < -ball->len) dvec[2] += ball->len;
+ else dvec[2] = 0.0;
+ break;
+ /* *** end deprecated *** */
+ }
+
+ /* ball->rad2 is inverse of squared rad */
+ dist2 = 1.0f - (len_squared_v3(dvec) * ball->rad2);
+
+ /* ball->s is negative if metaball is negative */
+ return (dist2 < 0.0f) ? 0.0f : (ball->s * dist2 * dist2 * dist2);
+}
+
+/**
+ * Computes density at given position form all metaballs which contain this point in their box.
+ * Traverses BVH using a queue.
+ */
+static float metaball(PROCESS *process, float x, float y, float z)
+{
+ int i;
+ float dens = 0.0f;
+ unsigned int front = 0, back = 0;
+ MetaballBVHNode *node;
+
+ process->bvh_queue[front++] = &process->metaball_bvh;
+
+ while (front != back) {
+ node = process->bvh_queue[back++];
+
+ for (i = 0; i < 2; i++) {
+ if ((node->bb[i].min[0] <= x) && (node->bb[i].max[0] >= x) &&
+ (node->bb[i].min[1] <= y) && (node->bb[i].max[1] >= y) &&
+ (node->bb[i].min[2] <= z) && (node->bb[i].max[2] >= z))
+ {
+ if (node->child[i]) process->bvh_queue[front++] = node->child[i];
+ else dens += densfunc(node->bb[i].ml, x, y, z);
+ }
+ }
+ }
+
+ return process->thresh - dens;
+}
+
+/**
+ * Adds face to indices, expands memory if needed.
+ */
+static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
+{
+ int *cur;
+
+#ifdef USE_ACCUM_NORMAL
+ float n[3];
+#endif
+
+ if (UNLIKELY(process->totindex == process->curindex)) {
+ process->totindex += 4096;
+ process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
+ }
+
+ cur = process->indices[process->curindex++];
+
+ /* displists now support array drawing, we treat tri's as fake quad */
+
+ cur[0] = i1;
+ cur[1] = i2;
+ cur[2] = i3;
+
+ if (i4 == 0) {
+ cur[3] = i3;
+ }
+ else {
+ cur[3] = i4;
+ }
+
+#ifdef USE_ACCUM_NORMAL
+ if (i4 == 0) {
+ normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]);
+ accumulate_vertex_normals(
+ 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(
+ 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]);
+ }
+#endif
+
+}
+
+/* Frees allocated memory */
+static void freepolygonize(PROCESS *process)
+{
+ if (process->corners) MEM_freeN(process->corners);
+ if (process->edges) MEM_freeN(process->edges);
+ if (process->centers) MEM_freeN(process->centers);
+ if (process->mainb) MEM_freeN(process->mainb);
+ if (process->bvh_queue) MEM_freeN(process->bvh_queue);
+ if (process->pgn_elements) BLI_memarena_free(process->pgn_elements);
+}
+
+/* **************** POLYGONIZATION ************************ */
+
+/**** Cubical Polygonization (optional) ****/
+
+#define LB 0 /* left bottom edge */
+#define LT 1 /* left top edge */
+#define LN 2 /* left near edge */
+#define LF 3 /* left far edge */
+#define RB 4 /* right bottom edge */
+#define RT 5 /* right top edge */
+#define RN 6 /* right near edge */
+#define RF 7 /* right far edge */
+#define BN 8 /* bottom near edge */
+#define BF 9 /* bottom far edge */
+#define TN 10 /* top near edge */
+#define TF 11 /* top far edge */
+
+static INTLISTS *cubetable[256];
+static char faces[256];
+
+/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
+static int corner1[12] = {
+ LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF
+};
+static int corner2[12] = {
+ LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF
+};
+static int leftface[12] = {
+ B, L, L, F, R, T, N, R, N, B, T, F
+};
+/* face on left when going corner1 to corner2 */
+static int rightface[12] = {
+ L, T, N, L, B, R, R, F, B, F, N, T
+};
+/* face on right when going corner1 to corner2 */
+
+/**
+ * triangulate the cube directly, without decomposition
+ */
+static void docube(PROCESS *process, CUBE *cube)
+{
+ INTLISTS *polys;
+ CORNER *c1, *c2;
+ int i, index = 0, count, indexar[8];
+
+ /* Determine which case cube falls into. */
+ for (i = 0; i < 8; i++) {
+ if (cube->corners[i]->value > 0.0f) {
+ index += (1 << i);
+ }
+ }
+
+ /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */
+ if (MB_BIT(faces[index], 0)) add_cube(process, cube->i - 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 1)) add_cube(process, cube->i + 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 2)) add_cube(process, cube->i, cube->j - 1, cube->k);
+ if (MB_BIT(faces[index], 3)) add_cube(process, cube->i, cube->j + 1, cube->k);
+ if (MB_BIT(faces[index], 4)) add_cube(process, cube->i, cube->j, cube->k - 1);
+ if (MB_BIT(faces[index], 5)) add_cube(process, cube->i, cube->j, cube->k + 1);
+
+ /* Using cubetable[], determines polygons for output. */
+ for (polys = cubetable[index]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ count = 0;
+ /* Sets needed vertex id's lying on the edges. */
+ for (edges = polys->list; edges; edges = edges->next) {
+ c1 = cube->corners[corner1[edges->i]];
+ c2 = cube->corners[corner2[edges->i]];
+
+ indexar[count] = vertid(process, c1, c2);
+ count++;
+ }
+
+ /* Adds faces to output. */
+ if (count > 2) {
+ switch (count) {
+ case 3:
+ make_face(process, indexar[2], indexar[1], indexar[0], 0);
+ break;
+ case 4:
+ if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ break;
+ case 5:
+ if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+
+ make_face(process, indexar[4], indexar[3], indexar[0], 0);
+ break;
+ case 6:
+ if (indexar[0] == 0) {
+ make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+ break;
+ case 7:
+ if (indexar[0] == 0) {
+ make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+
+ make_face(process, indexar[6], indexar[5], indexar[0], 0);
+
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * return corner with the given lattice location
+ * set (and cache) its function value
+ */
+static CORNER *setcorner(PROCESS *process, int i, int j, int k)
+{
+ /* for speed, do corner value caching here */
+ CORNER *c;
+ int index;
+
+ /* does corner exist? */
+ index = HASH(i, j, k);
+ c = process->corners[index];
+
+ for (; c != NULL; c = c->next) {
+ if (c->i == i && c->j == j && c->k == k) {
+ return c;
+ }
+ }
+
+ c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER));
+
+ c->i = i;
+ c->co[0] = ((float)i - 0.5f) * process->size;
+ c->j = j;
+ c->co[1] = ((float)j - 0.5f) * process->size;
+ c->k = k;
+ c->co[2] = ((float)k - 0.5f) * process->size;
+
+ c->value = metaball(process, c->co[0], c->co[1], c->co[2]);
+
+ c->next = process->corners[index];
+ process->corners[index] = c;
+
+ return c;
+}
+
+/**
+ * return next clockwise edge from given edge around given face
+ */
+static int nextcwedge(int edge, int face)
+{
+ switch (edge) {
+ case LB:
+ return (face == L) ? LF : BN;
+ case LT:
+ return (face == L) ? LN : TF;
+ case LN:
+ return (face == L) ? LB : TN;
+ case LF:
+ return (face == L) ? LT : BF;
+ case RB:
+ return (face == R) ? RN : BF;
+ case RT:
+ return (face == R) ? RF : TN;
+ case RN:
+ return (face == R) ? RT : BN;
+ case RF:
+ return (face == R) ? RB : TF;
+ case BN:
+ return (face == B) ? RB : LN;
+ case BF:
+ return (face == B) ? LB : RF;
+ case TN:
+ return (face == T) ? LT : RN;
+ case TF:
+ return (face == T) ? RT : LF;
+ }
+ return 0;
+}
+
+/**
+ * \return the face adjoining edge that is not the given face
+ */
+static int otherface(int edge, int face)
+{
+ int other = leftface[edge];
+ return face == other ? rightface[edge] : other;
+}
+
+/**
+ * create the 256 entry table for cubical polygonization
+ */
+static void makecubetable(void)
+{
+ static bool is_done = false;
+ int i, e, c, done[12], pos[8];
+
+ if (is_done) return;
+ is_done = true;
+
+ 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++)
+ if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
+ INTLIST *ints = NULL;
+ INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
+ int start = e, edge = e;
+
+ /* get face that is to right of edge from pos to neg corner: */
+ int face = pos[corner1[e]] ? rightface[e] : leftface[e];
+
+ while (1) {
+ edge = nextcwedge(edge, face);
+ done[edge] = 1;
+ if (pos[corner1[edge]] != pos[corner2[edge]]) {
+ INTLIST *tmp = ints;
+
+ ints = MEM_callocN(sizeof(INTLIST), "mball_intlist");
+ ints->i = edge;
+ ints->next = tmp; /* add edge to head of list */
+
+ if (edge == start) break;
+ face = otherface(edge, face);
+ }
+ }
+ lists->list = ints; /* add ints to head of table entry */
+ lists->next = cubetable[i];
+ cubetable[i] = lists;
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ INTLISTS *polys;
+ faces[i] = 0;
+ for (polys = cubetable[i]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ for (edges = polys->list; edges; edges = edges->next) {
+ if (edges->i == LB || edges->i == LT || edges->i == LN || edges->i == LF) faces[i] |= 1 << L;
+ if (edges->i == RB || edges->i == RT || edges->i == RN || edges->i == RF) faces[i] |= 1 << R;
+ if (edges->i == LB || edges->i == RB || edges->i == BN || edges->i == BF) faces[i] |= 1 << B;
+ if (edges->i == LT || edges->i == RT || edges->i == TN || edges->i == TF) faces[i] |= 1 << T;
+ if (edges->i == LN || edges->i == RN || edges->i == BN || edges->i == TN) faces[i] |= 1 << N;
+ if (edges->i == LF || edges->i == RF || edges->i == BF || edges->i == TF) faces[i] |= 1 << F;
+ }
+ }
+ }
+}
+
+void BKE_mball_cubeTable_free(void)
+{
+ int i;
+ INTLISTS *lists, *nlists;
+ INTLIST *ints, *nints;
+
+ for (i = 0; i < 256; i++) {
+ lists = cubetable[i];
+ while (lists) {
+ nlists = lists->next;
+
+ ints = lists->list;
+ while (ints) {
+ nints = ints->next;
+ MEM_freeN(ints);
+ ints = nints;
+ }
+
+ MEM_freeN(lists);
+ lists = nlists;
+ }
+ cubetable[i] = NULL;
+ }
+}
+
+/**** Storage ****/
+
+/**
+ * Inserts cube at lattice i, j, k into hash table, marking it as "done"
+ */
+static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k)
+{
+ int index;
+ CENTERLIST *newc, *l, *q;
+
+ index = HASH(i, j, k);
+ q = table[index];
+
+ for (l = q; l != NULL; l = l->next) {
+ if (l->i == i && l->j == j && l->k == k) return 1;
+ }
+
+ newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST));
+ newc->i = i;
+ newc->j = j;
+ newc->k = k;
+ newc->next = q;
+ table[index] = newc;
+
+ return 0;
+}
+
+/**
+ * Sets vid of vertex lying on given edge.
+ */
+static void setedge(
+ PROCESS *process,
+ int i1, int j1, int k1,
+ int i2, int j2, int k2,
+ int vid)
+{
+ int index;
+ EDGELIST *newe;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
+ newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST));
+
+ newe->i1 = i1;
+ newe->j1 = j1;
+ newe->k1 = k1;
+ newe->i2 = i2;
+ newe->j2 = j2;
+ newe->k2 = k2;
+ newe->vid = vid;
+ newe->next = process->edges[index];
+ process->edges[index] = newe;
+}
+
+/**
+ * \return vertex id for edge; return -1 if not set
+ */
+static int getedge(EDGELIST *table[],
+ int i1, int j1, int k1,
+ int i2, int j2, int k2)
+{
+ EDGELIST *q;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
+ for (; q != NULL; q = q->next) {
+ if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
+ q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
+ {
+ return q->vid;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Adds a vertex, expands memory if needed.
+ */
+static void addtovertices(PROCESS *process, const float v[3], const float no[3])
+{
+ if (process->curvertex == process->totvertex) {
+ process->totvertex += 4096;
+ process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
+ process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
+ }
+
+ copy_v3_v3(process->co[process->curvertex], v);
+ copy_v3_v3(process->no[process->curvertex], no);
+
+ process->curvertex++;
+}
+
+#ifndef USE_ACCUM_NORMAL
+/**
+ * Computes normal from density field at given point.
+ *
+ * \note Doesn't do normalization!
+ */
+static void vnormal(PROCESS *process, const float point[3], float r_no[3])
+{
+ const float delta = process->delta;
+ const float f = metaball(process, point[0], point[1], point[2]);
+
+ r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
+ r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
+ r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
+
+#if 0
+ f = normalize_v3(r_no);
+
+ if (0) {
+ float tvec[3];
+
+ delta *= 2.0f;
+
+ f = process->function(process, point[0], point[1], point[2]);
+
+ tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
+ tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
+ tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
+
+ if (normalize_v3(tvec) != 0.0f) {
+ add_v3_v3(r_no, tvec);
+ normalize_v3(r_no);
+ }
+ }
+#endif
+}
+#endif /* USE_ACCUM_NORMAL */
+
+/**
+ * \return the id of vertex between two corners.
+ *
+ * If it wasn't previously computed, does #converge() and adds vertex to process.
+ */
+static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2)
+{
+ float v[3], no[3];
+ int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
+
+ if (vid != -1) return vid; /* previously computed */
+
+ converge(process, c1, c2, v); /* position */
+
+#ifdef USE_ACCUM_NORMAL
+ zero_v3(no);
+#else
+ vnormal(process, v, no);
+#endif
+
+ addtovertices(process, v, no); /* save vertex */
+ vid = (int)process->curvertex - 1;
+ setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
+
+ return vid;
+}
+
+/**
+ * Given two corners, computes approximation of surface intersection point between them.
+ * In case of small threshold, do bisection.
+ */
+static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3])
+{
+ float tmp, dens;
+ unsigned int i;
+ float c1_value, c1_co[3];
+ float c2_value, c2_co[3];
+
+ if (c1->value < c2->value) {
+ c1_value = c2->value;
+ copy_v3_v3(c1_co, c2->co);
+ c2_value = c1->value;
+ copy_v3_v3(c2_co, c1->co);
+ }
+ else {
+ c1_value = c1->value;
+ copy_v3_v3(c1_co, c1->co);
+ c2_value = c2->value;
+ copy_v3_v3(c2_co, c2->co);
+ }
+
+
+ for (i = 0; i < process->converge_res; i++) {
+ interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f);
+ dens = metaball(process, r_p[0], r_p[1], r_p[2]);
+
+ if (dens > 0.0f) {
+ c1_value = dens;
+ copy_v3_v3(c1_co, r_p);
+ }
+ else {
+ c2_value = dens;
+ copy_v3_v3(c2_co, r_p);
+ }
+ }
+
+ tmp = -c1_value / (c2_value - c1_value);
+ interp_v3_v3v3(r_p, c1_co, c2_co, tmp);
+}
+
+/**
+ * Adds cube at given lattice position to cube stack of process.
+ */
+static void add_cube(PROCESS *process, int i, int j, int k)
+{
+ CUBES *ncube;
+ int n;
+
+ /* test if cube has been found before */
+ if (setcenter(process, process->centers, i, j, k) == 0) {
+ /* push cube on stack: */
+ ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES));
+ ncube->next = process->cubes;
+ process->cubes = ncube;
+
+ ncube->cube.i = i;
+ ncube->cube.j = j;
+ ncube->cube.k = k;
+
+ /* set corners of initial cube: */
+ for (n = 0; n < 8; n++)
+ ncube->cube.corners[n] = setcorner(process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0));
+ }
+}
+
+static void next_lattice(int r[3], const float pos[3], const float size)
+{
+ r[0] = (int)ceil((pos[0] / size) + 0.5f);
+ r[1] = (int)ceil((pos[1] / size) + 0.5f);
+ r[2] = (int)ceil((pos[2] / size) + 0.5f);
+}
+static void prev_lattice(int r[3], const float pos[3], const float size)
+{
+ next_lattice(r, pos, size);
+ r[0]--; r[1]--; r[2]--;
+}
+static void closest_latice(int r[3], const float pos[3], const float size)
+{
+ r[0] = (int)floorf(pos[0] / size + 1.0f);
+ r[1] = (int)floorf(pos[1] / size + 1.0f);
+ r[2] = (int)floorf(pos[2] / size + 1.0f);
+}
+
+/**
+ * Find at most 26 cubes to start polygonization from.
+ */
+static void find_first_points(PROCESS *process, const unsigned int em)
+{
+ const MetaElem *ml;
+ int center[3], lbn[3], rtf[3], it[3], dir[3], add[3];
+ float tmp[3], a, b;
+
+ ml = process->mainb[em];
+
+ mid_v3_v3v3(tmp, ml->bb->vec[0], ml->bb->vec[6]);
+ closest_latice(center, tmp, process->size);
+ prev_lattice(lbn, ml->bb->vec[0], process->size);
+ next_lattice(rtf, ml->bb->vec[6], process->size);
+
+ for (dir[0] = -1; dir[0] <= 1; dir[0]++) {
+ for (dir[1] = -1; dir[1] <= 1; dir[1]++) {
+ for (dir[2] = -1; dir[2] <= 1; dir[2]++) {
+ if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0) {
+ continue;
+ }
+
+ copy_v3_v3_int(it, center);
+
+ b = setcorner(process, it[0], it[1], it[2])->value;
+ do {
+ it[0] += dir[0];
+ it[1] += dir[1];
+ it[2] += dir[2];
+ a = b;
+ b = setcorner(process, it[0], it[1], it[2])->value;
+
+ if (a * b < 0.0f) {
+ add[0] = it[0] - dir[0];
+ add[1] = it[1] - dir[1];
+ add[2] = it[2] - dir[2];
+ DO_MIN(it, add);
+ add_cube(process, add[0], add[1], add[2]);
+ break;
+ }
+ } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) &&
+ (it[0] < rtf[0]) && (it[1] < rtf[1]) && (it[2] < rtf[2]));
+ }
+ }
+ }
+}
+
+/**
+ * The main polygonization proc.
+ * Allocates memory, makes cubetable,
+ * finds starting surface points
+ * and processes cubes on the stack until none left.
+ */
+static void polygonize(PROCESS *process)
+{
+ CUBE c;
+ unsigned int i;
+
+ process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
+ process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
+ process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
+ process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, "Metaball BVH Queue");
+
+ makecubetable();
+
+ for (i = 0; i < process->totelem; i++) {
+ find_first_points(process, i);
+ }
+
+ while (process->cubes != NULL) {
+ c = process->cubes->cube;
+ process->cubes = process->cubes->next;
+
+ docube(process, &c);
+ }
+}
+
+/**
+ * Iterates over ALL objects in the scene and all of its sets, including
+ * making all duplis(not only metas). Copies metas to mainb array.
+ * Computes bounding boxes for building BVH. */
+static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
+{
+ Scene *sce_iter = scene;
+ Base *base;
+ Object *bob;
+ MetaBall *mb;
+ const MetaElem *ml;
+ float obinv[4][4], obmat[4][4];
+ unsigned int i;
+ int obnr, zero_size = 0;
+ char obname[MAX_ID_NAME];
+ SceneBaseIter iter;
+
+ copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
+ invert_m4_m4(obinv, ob->obmat);
+
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* make main array */
+ BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
+ if (bob->type == OB_MBALL) {
+ zero_size = 0;
+ ml = NULL;
+
+ if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
+ mb = ob->data;
+
+ if (mb->editelems) ml = mb->editelems->first;
+ else ml = mb->elems.first;
+ }
+ else {
+ char name[MAX_ID_NAME];
+ int nr;
+
+ BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
+ if (STREQ(obname, name)) {
+ mb = bob->data;
+
+ if (mb->editelems) ml = mb->editelems->first;
+ else ml = mb->elems.first;
+ }
+ }
+
+ /* when metaball object has zero scale, then MetaElem to this MetaBall
+ * will not be put to mainb array */
+ if (has_zero_axis_m4(bob->obmat)) {
+ zero_size = 1;
+ }
+ else if (bob->parent) {
+ struct Object *pob = bob->parent;
+ while (pob) {
+ if (has_zero_axis_m4(pob->obmat)) {
+ zero_size = 1;
+ break;
+ }
+ pob = pob->parent;
+ }
+ }
+
+ if (zero_size) {
+ while (ml) {
+ ml = ml->next;
+ }
+ }
+ else {
+ while (ml) {
+ if (!(ml->flag & MB_HIDE)) {
+ float pos[4][4], rot[4][4];
+ float expx, expy, expz;
+ float tempmin[3], tempmax[3];
+
+ MetaElem *new_ml;
+
+ /* make a copy because of duplicates */
+ new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem));
+ *(new_ml) = *ml;
+ new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox));
+ new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+ new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+
+ /* too big stiffness seems only ugly due to linear interpolation
+ * no need to have possibility for too big stiffness */
+ if (ml->s > 10.0f) new_ml->s = 10.0f;
+ else new_ml->s = ml->s;
+
+ /* if metaball is negative, set stiffness negative */
+ if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s;
+
+ /* Translation of MetaElem */
+ unit_m4(pos);
+ pos[3][0] = ml->x;
+ pos[3][1] = ml->y;
+ pos[3][2] = ml->z;
+
+ /* Rotation of MetaElem is stored in quat */
+ quat_to_mat4(rot, ml->quat);
+
+ /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */
+ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
+ /* ml local space -> basis object space */
+ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
+
+ /* rad2 is inverse of squared radius */
+ new_ml->rad2 = 1 / (ml->rad * ml->rad);
+
+ /* initial dimensions = radius */
+ expx = ml->rad;
+ expy = ml->rad;
+ expz = ml->rad;
+
+ switch (ml->type) {
+ case MB_BALL:
+ break;
+ case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
+ expz += ml->expz;
+ /* fall through */
+ case MB_PLANE: /* plane is "expanded" by expy and expx */
+ expy += ml->expy;
+ /* fall through */
+ case MB_TUBE: /* tube is "expanded" by expx */
+ expx += ml->expx;
+ break;
+ case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
+ expx *= ml->expx;
+ expy *= ml->expy;
+ expz *= ml->expz;
+ break;
+ }
+
+ /* untransformed Bounding Box of MetaElem */
+ /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
+ copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
+ copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
+ copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
+ copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
+ copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
+ copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
+ copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
+ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
+
+ /* transformation of Metalem bb */
+ for (i = 0; i < 8; i++)
+ mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
+
+ /* find max and min of transformed bb */
+ INIT_MINMAX(tempmin, tempmax);
+ for (i = 0; i < 8; i++) {
+ DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax);
+ }
+
+ /* set only point 0 and 6 - AABB of Metaelem */
+ copy_v3_v3(new_ml->bb->vec[0], tempmin);
+ copy_v3_v3(new_ml->bb->vec[6], tempmax);
+
+ /* add new_ml to mainb[] */
+ if (UNLIKELY(process->totelem == process->mem)) {
+ process->mem = process->mem * 2 + 10;
+ process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
+ }
+ process->mainb[process->totelem++] = new_ml;
+ }
+ ml = ml->next;
+ }
+ }
+ }
+ }
+
+ /* compute AABB of all Metaelems */
+ if (process->totelem > 0) {
+ copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
+ copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
+ for (i = 1; i < process->totelem; i++)
+ make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
+ }
+}
+
+void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+{
+ MetaBall *mb;
+ DispList *dl;
+ unsigned int a;
+ PROCESS process = {0};
+
+ mb = ob->data;
+
+ process.thresh = mb->thresh;
+
+ if (process.thresh < 0.001f) process.converge_res = 16;
+ else if (process.thresh < 0.01f) process.converge_res = 8;
+ else if (process.thresh < 0.1f) process.converge_res = 4;
+ else process.converge_res = 2;
+
+ if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
+
+ if (eval_ctx->mode == DAG_EVAL_RENDER) {
+ process.size = mb->rendersize;
+ }
+ else {
+ process.size = mb->wiresize;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
+ process.size *= 2.0f;
+ }
+ }
+
+ process.delta = process.size * 0.001f;
+
+ process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
+
+ /* initialize all mainb (MetaElems) */
+ init_meta(eval_ctx, &process, scene, ob);
+
+ if (process.totelem > 0) {
+ build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
+
+ /* don't polygonize metaballs with too high resolution (base mball to small)
+ * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
+ if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
+ ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
+ ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2]))
+ {
+ polygonize(&process);
+
+ /* add resulting surface to displist */
+ if (process.curindex) {
+ dl = MEM_callocN(sizeof(DispList), "mballdisp");
+ BLI_addtail(dispbase, dl);
+ dl->type = DL_INDEX4;
+ dl->nr = (int)process.curvertex;
+ dl->parts = (int)process.curindex;
+
+ dl->index = (int *)process.indices;
+
+ for (a = 0; a < process.curvertex; a++) {
+ normalize_v3(process.no[a]);
+ }
+
+ dl->verts = (float *)process.co;
+ dl->nors = (float *)process.no;
+ }
+ }
+ }
+
+ freepolygonize(&process);
+}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 809d2137187..37a98eae58b 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -61,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
@@ -463,7 +464,7 @@ void BKE_mesh_free(Mesh *me, int unlink)
CustomData_free(&me->pdata, me->totpoly);
if (me->adt) {
- BKE_free_animdata(&me->id);
+ BKE_animdata_free(&me->id);
me->adt = NULL;
}
@@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
dl = dispbase->first;
while (dl) {
- int smooth = dl->rt & CU_SMOOTH ? 1 : 0;
+ const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
if (dl->type == DL_SEGM) {
startvert = vertcount;
@@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 3;
index += 3;
@@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 4;
@@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me)
}
}
+void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MAT_NR_REMAP(efa->mat_nr);
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < me->totpoly; i++) {
+ MAT_NR_REMAP(me->mpoly[i].mat_nr);
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
{
Mesh *me = meshOb->data;
@@ -1805,7 +1836,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
* Return a newly MEM_malloc'd array of all the mesh vertex locations
* \note \a r_numVerts may be NULL
*/
-float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
{
int i, numVerts = me->totvert;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1");
@@ -1821,8 +1852,9 @@ float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
* Find the index of the loop in 'poly' which references vertex,
* returns -1 if not found
*/
-int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart,
- unsigned vert)
+int poly_find_loop_from_vert(
+ const MPoly *poly, const MLoop *loopstart,
+ unsigned vert)
{
int j;
for (j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1838,20 +1870,22 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart,
* vertex. Returns the index of the loop matching vertex, or -1 if the
* vertex is not in \a poly
*/
-int poly_get_adj_loops_from_vert(unsigned r_adj[3], const MPoly *poly,
- const MLoop *mloop, unsigned vert)
+int poly_get_adj_loops_from_vert(
+ unsigned r_adj[2], const MPoly *poly,
+ const MLoop *mloop, unsigned vert)
{
int corner = poly_find_loop_from_vert(poly,
&mloop[poly->loopstart],
vert);
if (corner != -1) {
+#if 0 /* unused - this loop */
const MLoop *ml = &mloop[poly->loopstart + corner];
+#endif
/* vertex was found */
r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
- r_adj[1] = ml->v;
- r_adj[2] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
+ r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
}
return corner;
@@ -1887,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
{
int i;
MVert *mvert = me->mvert;
+ float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
for (i = 0; i < me->totvert; i++, mvert++)
mul_m4_v3(mat, mvert->co);
@@ -1901,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
}
}
- /* don't update normals, caller can do this explicitly */
+ /* don't update normals, caller can do this explicitly.
+ * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */
+ if (lnors) {
+ float m3[3][3];
+
+ copy_m3_m4(m3, mat);
+ normalize_m3(m3);
+ for (i = 0; i < me->totloop; i++, lnors++) {
+ mul_m3_v3(m3, *lnors);
+ }
+ }
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
@@ -2124,6 +2169,146 @@ 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)
+{
+ float (*r_loopnors)[3];
+ float (*polynors)[3];
+ short (*clnors)[2] = NULL;
+ bool free_polynors = false;
+
+ 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);
+ }
+ else {
+ r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+
+ /* may be NULL */
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+
+ if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
+ polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ free_polynors = false;
+ }
+ else {
+ polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
+ polynors, false);
+ free_polynors = true;
+ }
+
+ 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);
+
+ 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)
+{
+ const int num_verts = mesh->totvert;
+ const int num_edges = mesh->totedge;
+ const int num_polys = mesh->totpoly;
+ 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. */
+ 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++;
+ }
+ }
+ }
+ if (num_new_verts == 0) {
+ /* No new vertices are to be added, can do early exit. */
+ return;
+ }
+ /* Actual split. */
+ mesh->totvert += num_new_verts;
+ mesh->totedge += 2 * num_new_verts;
+ mvert = mesh->mvert = MEM_reallocN(mesh->mvert,
+ sizeof(MVert) * mesh->totvert);
+ medge = mesh->medge = MEM_reallocN(mesh->medge,
+ sizeof(MEdge) * mesh->totedge);
+ CustomData_set_layer(&mesh->vdata, CD_MVERT, mesh->mvert);
+ CustomData_set_layer(&mesh->edata, CD_MEDGE, mesh->medge);
+ 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;
+ }
+ else {
+ medge[new_edge].v2 = new_vert;
+ }
+
+ ml->v = new_vert;
+ ml_prev->e = new_edge_prev;
+ ml->e = new_edge;
+ num_new_verts++;
+ }
+ }
+ }
+}
+
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
@@ -2213,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object(
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = DAG_EVAL_RENDER;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
@@ -2339,3 +2524,15 @@ Mesh *BKE_mesh_new_from_object(
return tmpmesh;
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Mesh *mesh)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, mesh->id.name);
+ }
+ if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(mesh);
+ }
+}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 6c835a72a40..d17ca751c5e 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -226,7 +226,7 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly
MPoly *mp;
if (only_face_normals) {
- BLI_assert(pnors != NULL);
+ BLI_assert((pnors != NULL) || (numPolys == 0));
#pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT)
for (i = 0; i < numPolys; i++) {
@@ -252,12 +252,12 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly
}
}
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
for (i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
float *no = tnorms[i];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
normalize_v3_v3(no, mv->co);
}
@@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
/* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
* tag it as invalid and abort. */
lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+
+ if (edge_vectors) {
+ BLI_stack_clear(edge_vectors);
+ }
return;
}
@@ -1349,6 +1353,10 @@ static void mesh_normals_loop_custom_set(
const int nidx = lidx;
float *nor = custom_loopnors[nidx];
+ if (is_zero_v3(nor)) {
+ nor = lnors[nidx];
+ }
+
if (!org_nor) {
org_nor = nor;
}
@@ -1408,6 +1416,10 @@ static void mesh_normals_loop_custom_set(
const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
float *nor = custom_loopnors[nidx];
+ if (is_zero_v3(nor)) {
+ nor = lnors[nidx];
+ }
+
nbr_nors++;
add_v3_v3(avg_nor, nor);
BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
@@ -2245,12 +2257,15 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
/**
* Recreate tessellation.
*
- * \param do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces.
+ * \param do_face_nor_copy: Controls whether the normals from the poly are copied to the tessellated faces.
*
* \return number of tessellation faces.
*/
-int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy)
+int BKE_mesh_recalc_tessellation(
+ CustomData *fdata, CustomData *ldata, CustomData *pdata,
+ MVert *mvert,
+ int totface, int totloop, int totpoly,
+ const bool do_face_nor_copy)
{
/* use this to avoid locking pthread for _every_ polygon
* and calling the fill function */
@@ -2460,7 +2475,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
- if (do_face_nor_cpy) {
+ if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
* avoid the need to recalculate normals later */
if (CustomData_has_layer(pdata, CD_NORMAL)) {
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 8d9fbe46f19..1d8978586b6 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -30,7 +30,9 @@
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
+#include "DNA_vec_types.h"
+#include "BLI_buffer.h"
#include "BLI_utildefines.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
@@ -52,8 +54,10 @@
/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
* but for now this replaces it because its unused. */
-UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert, int selected, float *limit)
+UvVertMap *BKE_mesh_uv_vert_map_create(
+ struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
+ unsigned int totpoly, unsigned int totvert,
+ const float limit[2], const bool selected, const bool use_winding)
{
UvVertMap *vmap;
UvMapVert *buf;
@@ -61,6 +65,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
unsigned int a;
int i, totuv, nverts;
+ bool *winding;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32);
+
totuv = 0;
/* generate UvMapVert array */
@@ -73,11 +80,11 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
return NULL;
vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
- if (!vmap)
- return NULL;
-
- vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert");
+ vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
+ if (use_winding) {
+ winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
+ }
if (!vmap->vert || !vmap->buf) {
BKE_mesh_uv_vert_map_free(vmap);
@@ -87,6 +94,12 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
mp = mpoly;
for (a = 0; a < totpoly; a++, mp++) {
if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, mp->totloop);
+ }
+
nverts = mp->totloop;
for (i = 0; i < nverts; i++) {
@@ -95,8 +108,17 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
buf->separate = 0;
buf->next = vmap->vert[mloop[mp->loopstart + i].v];
vmap->vert[mloop[mp->loopstart + i].v] = buf;
+
+ if (use_winding) {
+ copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv);
+ }
+
buf++;
}
+
+ if (use_winding) {
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0;
+ }
}
}
@@ -123,7 +145,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1]) {
+ if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] &&
+ (!use_winding || winding[iterv->f] == winding[v->f]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -141,6 +165,12 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
vmap->vert[a] = newvlist;
}
+ if (use_winding) {
+ MEM_freeN(winding);
+ }
+
+ BLI_buffer_free(&tf_uv_buf);
+
return vmap;
}
@@ -159,8 +189,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
}
/**
-
-
* Generates a map where the key is the vertex and the value is a list
* of polys or loops that use that vertex as a corner. The lists are allocated
* from one memory pool.
@@ -233,9 +261,10 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/* Generates a map where the key is the vertex and the value is a list
- * of edges that use that vertex as an endpoint. The lists are allocated
- * from one memory pool. */
+/**
+ * Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *medge, int totvert, int totedge)
{
@@ -275,6 +304,10 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
*r_mem = indices;
}
+/**
+ * Generates a map where the key is the edge and the value is a list of polygons that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *UNUSED(medge), const int totedge,
const MPoly *mpoly, const int totpoly,
@@ -382,7 +415,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem,
* Used currently for UVs and 'smooth groups'.
* \{ */
-/** Callback deciding whether the given poly/loop/edge define an island boundary or not.
+/**
+ * Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
typedef bool (*MeshRemap_CheckIslandBoundary)(
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
@@ -565,8 +599,7 @@ static void poly_edge_loop_islands_calc(
}
static bool poly_is_island_boundary_smooth_cb(
- const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me,
- const int nbr_egde_users)
+ const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users)
{
/* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
@@ -663,7 +696,6 @@ void BKE_mesh_loop_islands_add(
const size_t curr_num_islands = (size_t)island_store->islands_num;
int i = item_num;
- island_store->items_to_islands_num = item_num;
while (i--) {
island_store->items_to_islands[items_indices[i]] = curr_island_idx;
}
@@ -698,17 +730,21 @@ void BKE_mesh_loop_islands_add(
* not sure we want that at all!
*/
static bool mesh_check_island_boundary_uv(
- const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me,
- const int UNUSED(nbr_egde_users))
+ const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users))
{
/* Edge is UV boundary if tagged as seam. */
return (me->flag & ME_SEAM) != 0;
}
/**
- * \note all this could be optimized...
- * Not sure it would be worth the more complex code, though, those loops
- * are supposed to be really quick to do...
+ * Calculate UV islands.
+ *
+ * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity,
+ * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams
+ * will not be handled correctly...
+ *
+ * \note All this could be optimized...
+ * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
*/
bool BKE_mesh_calc_islands_loop_poly_uv(
MVert *UNUSED(verts), const int UNUSED(totvert),
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index aca72614094..0ed10687fae 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BLI_space_transform_apply_normal(space_transform, v2_no);
}
- fill_vn_fl(weights, (int)numedges_src, 0.0f);
+ copy_vn_fl(weights, (int)numedges_src, 0.0f);
/* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
* with lower/upper bounds. */
@@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*poly_nors_dst)[3] = NULL;
float (*loop_nors_dst)[3] = NULL;
+ float (*poly_cents_src)[3] = NULL;
+
MeshElemMap *vert_to_loop_map_src = NULL;
int *vert_to_loop_map_src_buff = NULL;
MeshElemMap *vert_to_poly_map_src = NULL;
@@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
int *indices_interp = NULL;
float *weights_interp = NULL;
+ MLoop *ml_src, *ml_dst;
+ MPoly *mp_src, *mp_dst;
int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
IslandResult **islands_res;
@@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src);
if (use_from_vert) {
loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__);
- for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) {
- MPoly *mp = &polys_src[pidx_src];
- for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) {
+ poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
+ for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
+ ml_src = &loops_src[mp_src->loopstart];
+ for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) {
loop_to_poly_map_src[lidx_src] = pidx_src;
}
+ BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
}
}
@@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_verts_active = 0;
BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src);
for (i = 0; i < isld->count; i++) {
- MPoly *mp_src = &polys_src[isld->indices[i]];
+ mp_src = &polys_src[isld->indices[i]];
for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) {
- BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
- num_verts_active++;
+ const unsigned int vidx_src = loops_src[lidx_src].v;
+ if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
+ BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
+ num_verts_active++;
+ }
}
}
/* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
@@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_faces_active = 0;
BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src);
for (i = 0; i < num_faces_src; i++) {
- MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]];
+ mp_src = &polys_src[tessface_to_poly_map_src[i]];
if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
BLI_BITMAP_ENABLE(faces_active, i);
num_faces_active++;
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
+ /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_faces_ex(
&treedata[tindex], verts_src, verts_allocated_src,
faces_src, num_faces_src, faces_allocated_src,
@@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm(
islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
}
- for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) {
- MPoly *mp_dst = &polys_dst[pidx_dst];
+ for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst];
+ /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
+ * corner to use from normals only. */
+ float pcent_dst[3];
+ bool pcent_dst_valid = false;
+
if ((size_t)mp_dst->totloop > islands_res_buff_size) {
islands_res_buff_size = (size_t)mp_dst->totloop;
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (tindex = 0; tindex < num_trees; tindex++) {
BVHTreeFromMesh *tdata = &treedata[tindex];
- MLoop *ml_dst = &loops_dst[mp_dst->loopstart];
+ ml_dst = &loops_dst[mp_dst->loopstart];
for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
if (use_from_vert) {
float tmp_co[3];
@@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*nor_dst)[3];
float (*nors_src)[3];
float best_nor_dot = -2.0f;
+ float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
@@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
- if (dot > best_nor_dot) {
- best_nor_dot = dot;
- best_index_src = index_src;
+
+ pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ loop_to_poly_map_src[index_src] : index_src;
+ /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
+ * to check we stay on current island (all loops from a given poly are
+ * on same island!). */
+ lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ index_src : polys_src[pidx_src].loopstart;
+
+ /* A same vert may be at the boundary of several islands! Hence, we have to ensure
+ * poly/loop we are currently considering *belongs* to current island! */
+ if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
+ continue;
+ }
+
+ if (dot > best_nor_dot - 1e-6f) {
+ /* We need something as fallback decision in case dest normal matches several
+ * source normals (see T44522), using distance between polys' centers here. */
+ float *pcent_src;
+ float sqdist;
+
+ mp_src = &polys_src[pidx_src];
+ ml_src = &loops_src[mp_src->loopstart];
+
+ if (!pcent_dst_valid) {
+ BKE_mesh_calc_poly_center(
+ mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
+ pcent_dst_valid = true;
+ }
+ pcent_src = poly_cents_src[pidx_src];
+ sqdist = len_squared_v3v3(pcent_dst, pcent_src);
+
+ if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
+ best_nor_dot = dot;
+ best_sqdist_fallback = sqdist;
+ best_index_src = index_src;
+ }
}
}
if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
/* Our best_index_src is a poly one for now!
* Have to find its loop matching our closest vertex. */
- MPoly *mp_src = &polys_src[best_index_src];
- MLoop *ml_src = &loops_src[mp_src->loopstart];
+ mp_src = &polys_src[best_index_src];
+ ml_src = &loops_src[mp_src->loopstart];
for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
if ((int)ml_src->v == nearest.index) {
best_index_src = plidx_src + mp_src->loopstart;
@@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f;
+ best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
+ islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f;
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = best_index_src;
}
@@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest one for now).
* Note we could be much more subtle here, again that's for later... */
- MPoly *mp_src;
- MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst];
int j;
float best_dist_sq = FLT_MAX;
float tmp_co[3];
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Else, we use source poly, indices stored in islands_res are those of polygons. */
pidx_src = isld_res->index_src;
if (pidx_src >= 0) {
- MPoly *mp_src = &polys_src[pidx_src];
float *hit_co = isld_res->hit_point;
int best_loop_index_src;
+ mp_src = &polys_src[pidx_src];
/* If prev and curr poly are the same, no need to do anything more!!! */
if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
int pidx_isld_src, pidx_isld_src_prev;
@@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest point on poly for now).
* Note we could be much more subtle here, again that's for later... */
- MLoop *ml_dst = &loops_dst[lidx_dst];
float best_dist_sq = FLT_MAX;
float tmp_co[3];
int j;
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (loop_to_poly_map_src) {
MEM_freeN(loop_to_poly_map_src);
}
+ if (poly_cents_src) {
+ MEM_freeN(poly_cents_src);
+ }
if (vcos_interp) {
MEM_freeN(vcos_interp);
}
@@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BLI_space_transform_apply_normal(space_transform, tmp_no);
}
- fill_vn_fl(weights, (int)numpolys_src, 0.0f);
+ copy_vn_fl(weights, (int)numpolys_src, 0.0f);
if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
tmp_poly_size = (size_t)mp->totloop;
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 7de993e1099..418c2911b5b 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -500,13 +500,13 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (mp->loopstart < 0 || mp->totloop < 3) {
/* Invalid loop data. */
- PRINT_ERR("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n",
+ PRINT_ERR("\tPoly %u is invalid (loopstart: %d, totloop: %d)\n",
sp->index, mp->loopstart, mp->totloop);
sp->invalid = true;
}
else if (mp->loopstart + mp->totloop > totloop) {
/* Invalid loop data. */
- PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n",
+ PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)\n",
sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
sp->invalid = true;
}
@@ -552,7 +552,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
/* Edge not existing. */
- PRINT_ERR("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2);
+ PRINT_ERR("\tPoly %u needs missing edge (%d, %d)\n", sp->index, v1, v2);
if (do_fixes)
recalc_flag.edges = true;
else
@@ -564,7 +564,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
- PRINT_ERR("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n",
+ PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u\n",
sp->loopstart + j, prev_e, ml->e);
}
else {
@@ -580,7 +580,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
- PRINT_ERR("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n",
+ PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n",
sp->index, prev_e, ml->e);
}
else {
@@ -602,7 +602,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (*v != *prev_v) {
int dlt = v - prev_v;
if (dlt > 1) {
- PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
+ PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %d (%d times)\n",
sp->index, *prev_v, dlt);
sp->invalid = true;
}
@@ -610,7 +610,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
}
if (v - prev_v > 1) { /* Don't forget final verts! */
- PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
+ PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %d (%d times)\n",
sp->index, *prev_v, (int)(v - prev_v));
sp->invalid = true;
}
@@ -689,10 +689,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
if (do_verbose) {
- PRINT_ERR("\tPolys %u and %u use same vertices (%u",
+ PRINT_ERR("\tPolys %u and %u use same vertices (%d",
prev_sp->index, sp->index, *p1_v);
for (j = 1; j < p1_nv; j++)
- PRINT_ERR(", %u", p1_v[j]);
+ PRINT_ERR(", %d", p1_v[j]);
PRINT_ERR("), considering poly %u as invalid.\n", sp->index);
}
else {
@@ -741,7 +741,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
/* Multi-used loops. */
else if (prev_end > sp->loopstart) {
- PRINT_ERR("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n",
+ PRINT_ERR("\tPolys %u and %u share loops from %d to %d, considering poly %u as invalid.\n",
prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
if (do_fixes) {
REMOVE_POLY_TAG((&mpolys[sp->index]));
@@ -846,7 +846,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
int tot_elem = 0;
if (msel->index < 0) {
- PRINT_ERR("\tMesh select element %d type %d index is negative, "
+ PRINT_ERR("\tMesh select element %u type %d index is negative, "
"resetting selection stack.\n", i, msel->type);
free_flag.mselect = do_fixes;
break;
@@ -865,7 +865,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
if (msel->index > tot_elem) {
- PRINT_ERR("\tMesh select element %d type %d index %d is larger than data array size %d, "
+ PRINT_ERR("\tMesh select element %u type %d index %d is larger than data array size %d, "
"resetting selection stack.\n", i, msel->type, msel->index, tot_elem);
free_flag.mselect = do_fixes;
@@ -1475,8 +1475,9 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
int j, v_prev = (l + (mp->totloop - 1))->v;
for (j = 0; j < mp->totloop; j++, l++) {
if (v_prev != l->v) {
- if (!BLI_edgehash_haskey(eh, v_prev, l->v)) {
- BLI_edgehash_insert(eh, v_prev, l->v, NULL);
+ void **val_p;
+ if (!BLI_edgehash_ensure_p(eh, v_prev, l->v, &val_p)) {
+ *val_p = NULL;
}
}
v_prev = l->v;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 42247d866e4..1f6d40dafa3 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -101,7 +101,7 @@ void BKE_modifier_init(void)
virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
}
-ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
@@ -116,7 +116,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
ModifierData *modifier_new(int type)
{
- ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(type);
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
/* note, this name must be made unique later */
@@ -135,7 +135,7 @@ ModifierData *modifier_new(int type)
void modifier_free(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->freeData) mti->freeData(md);
if (md->error) MEM_freeN(md->error);
@@ -146,7 +146,7 @@ void modifier_free(ModifierData *md)
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
if (modifiers && md) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
}
@@ -155,14 +155,14 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
bool modifier_dependsOnTime(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
bool modifier_supportsMapping(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->type == eModifierTypeType_OnlyDeform ||
(mti->flags & eModifierTypeFlag_SupportsMapping));
@@ -170,7 +170,7 @@ bool modifier_supportsMapping(ModifierData *md)
bool modifier_isPreview(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
/* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) {
@@ -221,7 +221,7 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk,
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachObjectLink)
mti->foreachObjectLink(md, ob, walk, userData);
@@ -233,7 +233,7 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
else if (mti->foreachObjectLink) {
@@ -249,7 +249,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachTexLink)
mti->foreachTexLink(md, ob, walk, userData);
@@ -261,7 +261,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
*/
void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
const size_t data_size = sizeof(ModifierData);
const char *md_src_data = ((const char *)md_src) + data_size;
char *md_dst_data = ((char *)md_dst) + data_size;
@@ -271,7 +271,7 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
void modifier_copyData(ModifierData *md, ModifierData *target)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
@@ -282,7 +282,7 @@ void modifier_copyData(ModifierData *md, ModifierData *target)
bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -293,7 +293,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -305,13 +305,13 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
bool modifier_isSameTopology(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
}
bool modifier_isNonGeometrical(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->type == eModifierTypeType_NonGeometrical);
}
@@ -353,7 +353,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
/* Find the last modifier acting on the cage. */
for (i = 0; md; i++, md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool supports_mapping;
md->scene = scene;
@@ -411,7 +411,7 @@ bool modifiers_isParticleEnabled(Object *ob)
bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -432,7 +432,7 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierDat
/* build a list of modifier data requirements in reverse order */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
@@ -626,7 +626,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
bool modifier_isCorrectableDeformed(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->deformMatricesEM != NULL);
}
@@ -736,7 +736,7 @@ struct DerivedMesh *modwrap_applyModifier(
struct DerivedMesh *dm,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -751,7 +751,7 @@ struct DerivedMesh *modwrap_applyModifierEM(
DerivedMesh *dm,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -766,7 +766,7 @@ void modwrap_deformVerts(
float (*vertexCos)[3], int numVerts,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -780,7 +780,7 @@ void modwrap_deformVertsEM(
struct BMEditMesh *em, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 645567eea67..18f3db6bd15 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -37,8 +37,9 @@
#include "BKE_editmesh.h"
/* Static function for alloc */
-static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(
+ MPoly *mp, MLoop *ml,
+ BMesh *bm, BMVert **vtable, BMEdge **etable)
{
BMVert **verts = BLI_array_alloca(verts, mp->totloop);
BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 73f75f4f96d..74758ae508b 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -222,7 +222,7 @@ static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user,
colorspace = clip->colorspace_settings.name;
}
- loadflag = IB_rect | IB_multilayer | IB_alphamode_detect;
+ loadflag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
/* read ibuf */
ibuf = IMB_loadiffname(name, loadflag, colorspace);
@@ -1129,15 +1129,15 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
}
/* get segments of cached frames. useful for debugging cache policies */
-void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r)
+void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points)
{
- *totseg_r = 0;
- *points_r = NULL;
+ *r_totseg = 0;
+ *r_points = NULL;
if (clip->cache) {
int proxy = rendersize_to_proxy(user, clip->flag);
- IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r);
+ IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points);
}
}
@@ -1168,7 +1168,7 @@ static void free_buffers(MovieClip *clip)
clip->anim = NULL;
}
- BKE_free_animdata((ID *) clip);
+ BKE_animdata_free((ID *) clip);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 220d0f7c604..0c984c38b8e 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -280,7 +280,7 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
ModifierData *md = (ModifierData *)mmd;
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
DerivedMesh *dm;
@@ -340,13 +340,13 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd,
bool render, bool ignore_simplify)
{
if (render)
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl) : mmd->renderlvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl;
else if (ob->mode == OB_MODE_SCULPT)
return mmd->sculptlvl;
else if (ignore_simplify)
return mmd->lvl;
else
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -429,7 +429,7 @@ int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *ds
int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm, *ndm;
int numVerts, result;
float (*deformedVerts)[3];
@@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
{
Mesh *me = ob->data;
MDisps *mdisps;
- int lvl = mmd->totlvl;
+ const int lvl = mmd->totlvl;
if ((totlvl > multires_max_levels) || (me->totpoly == 0))
return;
+ BLI_assert(totlvl > lvl);
+
multires_force_update(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps)
mdisps = multires_mdisps_initialize_hidden(me, totlvl);
- if (mdisps->disps && !updateblock && totlvl > 1) {
+ if (mdisps->disps && !updateblock && lvl != 0) {
/* upsample */
DerivedMesh *lowdm, *cddm, *highdm;
CCGElem **highGridData, **lowGridData, **subGridData;
@@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create multires DM from original mesh at low level */
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ BLI_assert(lowdm != cddm);
cddm->release(cddm);
/* copy subsurf grids and replace them with low displaced grids */
@@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me)
me->mr = NULL;
}
-/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them
- * such that 'ob' has the same total number of levels as 'to_ob'. */
-static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
+/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
+ * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
+void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
- MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1);
+ if (mmd_src->totlvl == mmd_dst->totlvl) {
+ return;
+ }
+
+ if (mmd_src->totlvl > mmd_dst->totlvl) {
+ multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ }
+ else {
+ multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
+ }
+}
- if (!mmd) {
+static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
+ MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
+
+ if (!mmd_src) {
/* object could have MDISP even when there is no multires modifier
* this could lead to troubles due to i've got no idea how mdisp could be
* upsampled correct without modifier data.
* just remove mdisps if no multires present (nazgul) */
- multires_customdata_delete(ob->data);
+ multires_customdata_delete(ob_src->data);
}
- if (mmd && to_mmd) {
- if (mmd->totlvl > to_mmd->totlvl)
- multires_del_higher(mmd, ob, to_mmd->totlvl);
- else
- multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple);
+ if (mmd_src && mmd_dst) {
+ multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
}
}
@@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob)
void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
- multires_sync_levels(scene, ob, to_ob);
+ multires_sync_levels(scene, to_ob, ob);
/* construct scale matrix for displacement */
BKE_object_scale_to_mat3(to_ob, tmat);
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 9a04312aaab..1ad6446eb05 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -535,9 +535,14 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* if the active-strip info has been stored already, access this, otherwise look this up
* and store for (very probable) future usage
*/
+ if (adt->act_track == NULL) {
+ if (adt->actstrip)
+ adt->act_track = BKE_nlatrack_find_tweaked(adt);
+ else
+ adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
+ }
if (adt->actstrip == NULL) {
- NlaTrack *nlt = BKE_nlatrack_find_active(&adt->nla_tracks);
- adt->actstrip = BKE_nlastrip_find_active(nlt);
+ adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
}
strip = adt->actstrip;
@@ -926,6 +931,39 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
return NULL;
}
+/* Get the NLA Track that the active action/action strip comes from,
+ * since this info is not stored in AnimData. It also isn't as simple
+ * as just using the active track, since multiple tracks may have been
+ * entered at the same time.
+ */
+NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
+{
+ NlaTrack *nlt;
+
+ /* sanity check */
+ if (adt == NULL)
+ return NULL;
+
+ /* Since the track itself gets disabled, we want the first disabled... */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
+ /* For good measure, make sure that strip actually exists there */
+ if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
+ return nlt;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
+ __func__,
+ adt->actstrip, (adt->actstrip) ? adt->actstrip->name : "<None>",
+ nlt, nlt->name);
+ }
+ }
+ }
+
+ /* Not found! */
+ return NULL;
+}
+
/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
* that has this status in its AnimData block.
*/
@@ -1584,6 +1622,12 @@ bool BKE_nla_action_stash(AnimData *adt)
nlt = add_nlatrack(adt, prev_track);
BLI_assert(nlt != NULL);
+ /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
+ if (prev_track == NULL) {
+ BLI_remlink(&adt->nla_tracks, nlt);
+ BLI_addhead(&adt->nla_tracks, nlt);
+ }
+
BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
BLI_uniquename(&adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
@@ -1605,6 +1649,12 @@ bool BKE_nla_action_stash(AnimData *adt)
nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
+ /* also mark the strip for auto syncing the length, so that the strips accurately
+ * reflect the length of the action
+ * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
+ */
+ strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+
/* succeeded */
return true;
}
@@ -1756,6 +1806,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
*/
adt->tmpact = adt->action;
adt->action = activeStrip->act;
+ adt->act_track = activeTrack;
adt->actstrip = activeStrip;
id_us_plus(&activeStrip->act->id);
adt->flag |= ADT_NLA_EDIT_ON;
@@ -1815,6 +1866,7 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
if (adt->action) adt->action->id.us--;
adt->action = adt->tmpact;
adt->tmpact = NULL;
+ adt->act_track = NULL;
adt->actstrip = NULL;
adt->flag &= ~ADT_NLA_EDIT_ON;
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index c7010e42aac..8ac0a8a31f6 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -62,6 +62,7 @@
#include "BKE_node.h"
#include "BLI_ghash.h"
+#include "BLI_threads.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -287,6 +288,7 @@ void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
static GHash *nodetreetypes_hash = NULL;
static GHash *nodetypes_hash = NULL;
static GHash *nodesockettypes_hash = NULL;
+static SpinLock spin;
bNodeTreeType *ntreeTypeFind(const char *idname)
{
@@ -303,7 +305,7 @@ bNodeTreeType *ntreeTypeFind(const char *idname)
void ntreeTypeAdd(bNodeTreeType *nt)
{
- BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, nt, NULL, NULL, false);
}
@@ -317,7 +319,7 @@ static void ntree_free_type(void *treetype_v)
MEM_freeN(treetype);
}
-void ntreeTypeFreeLink(bNodeTreeType *nt)
+void ntreeTypeFreeLink(const bNodeTreeType *nt)
{
BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
}
@@ -378,7 +380,7 @@ void nodeRegisterType(bNodeType *nt)
BLI_assert(nt->idname[0] != '\0');
BLI_assert(nt->poll != NULL);
- BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, NULL, nt, NULL, false);
}
@@ -1109,7 +1111,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
* copying for internal use (threads for eg), where you wont want it to modify the
* scene data.
*/
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews)
+static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
{
bNodeTree *newtree;
bNode *node /*, *nnode */ /* UNUSED */, *last;
@@ -1119,7 +1121,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
if (ntree == NULL) return NULL;
/* is ntree part of library? */
- if (bmain && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
+ if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
newtree = BKE_libblock_copy(&ntree->id);
}
else {
@@ -1131,6 +1133,8 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
/* in case a running nodetree is copied */
newtree->execdata = NULL;
+
+ newtree->duplilock = NULL;
BLI_listbase_clear(&newtree->nodes);
BLI_listbase_clear(&newtree->links);
@@ -1211,7 +1215,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true);
+ return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree)
{
@@ -1418,7 +1422,7 @@ static void node_preview_sync(bNodePreview *to, bNodePreview *from)
if (to->rect && from->rect) {
int xsize = to->xsize;
int ysize = to->ysize;
- memcpy(to->rect, from->rect, 4 * xsize + xsize * ysize * sizeof(char) * 4);
+ memcpy(to->rect, from->rect, xsize * ysize * sizeof(char) * 4);
}
}
@@ -1733,7 +1737,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
/* unregister associated RNA types */
ntreeInterfaceTypeFree(ntree);
- BKE_free_animdata((ID *)ntree);
+ BKE_animdata_free((ID *)ntree);
id_us_min((ID *)ntree->gpd);
@@ -1775,6 +1779,9 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
if (ntree->previews) {
BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
}
+
+ if (ntree->duplilock)
+ BLI_mutex_free(ntree->duplilock);
/* if ntree is not part of library, free the libblock data explicitly */
for (tntree = G.main->nodetree.first; tntree; tntree = tntree->id.next)
@@ -1962,56 +1969,67 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
if (ntree) {
bNodeTree *ltree;
bNode *node;
-
+ AnimData *adt;
+
bAction *action_backup = NULL, *tmpact_backup = NULL;
-
+
+ BLI_spin_lock(&spin);
+ if (!ntree->duplilock) {
+ ntree->duplilock = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
+
+ BLI_mutex_lock(ntree->duplilock);
+
/* Workaround for copying an action on each render!
* set action to NULL so animdata actions don't get copied */
- AnimData *adt = BKE_animdata_from_id(&ntree->id);
-
+ adt = BKE_animdata_from_id(&ntree->id);
+
if (adt) {
action_backup = adt->action;
tmpact_backup = adt->tmpact;
-
+
adt->action = NULL;
adt->tmpact = NULL;
}
-
+
/* Make full copy.
* Note: previews are not copied here.
*/
- ltree = ntreeCopyTree_internal(ntree, NULL, false, false, false);
+ ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false);
ltree->flag |= NTREE_IS_LOCALIZED;
-
+
for (node = ltree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP && node->id) {
node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
}
}
-
+
if (adt) {
AnimData *ladt = BKE_animdata_from_id(&ltree->id);
-
+
adt->action = ladt->action = action_backup;
adt->tmpact = ladt->tmpact = tmpact_backup;
-
+
if (action_backup) action_backup->id.us++;
if (tmpact_backup) tmpact_backup->id.us++;
-
+
}
/* end animdata uglyness */
-
+
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
-
+
for (node = ntree->nodes.first; node; node = node->next) {
/* store new_node pointer to original */
node->new_node->new_node = node;
}
-
+
if (ntree->typeinfo->localize)
ntree->typeinfo->localize(ltree, ntree);
-
+
+ BLI_mutex_unlock(ntree->duplilock);
+
return ltree;
}
else
@@ -3082,10 +3100,14 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
bNodeSocket *sock;
Material *ma = (Material *)node->id;
int a;
+ short check_flags = SOCK_UNAVAIL;
+
+ if (!copy_to_id)
+ check_flags |= SOCK_HIDDEN;
/* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) {
- if (!nodeSocketIsHidden(sock)) {
+ if (!(sock->flag & check_flags)) {
if (copy_to_id) {
switch (a) {
case MAT_IN_COLOR:
@@ -3475,6 +3497,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_bokehimage();
register_node_type_cmp_bokehblur();
register_node_type_cmp_switch();
+ register_node_type_cmp_switch_view();
register_node_type_cmp_pixelate();
register_node_type_cmp_mask();
@@ -3625,6 +3648,7 @@ void init_nodesystem(void)
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
nodesockettypes_hash = BLI_ghash_str_new("nodesockettypes_hash gh");
+ BLI_spin_init(&spin);
register_undefined_types();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d63e2516805..647aadf237c 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -96,6 +96,7 @@
#include "BKE_editmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
+#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -234,7 +235,7 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
{
- ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
mti = modifierType_getInfo(modifier_type);
@@ -247,7 +248,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
+void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst);
@@ -263,8 +264,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (ELEM(md->type,
eModifierType_Hook,
- eModifierType_Softbody,
- eModifierType_ParticleInstance,
eModifierType_Collision))
{
continue;
@@ -272,21 +271,31 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (!BKE_object_support_modifier_type_check(ob_dst, md->type))
continue;
-
- if (md->type == eModifierType_Skin) {
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
+
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
}
nmd = modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
+
modifier_copyData(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
modifier_unique_name(&ob_dst->modifiers, nmd);
}
BKE_object_copy_particlesystems(ob_dst, ob_src);
- BKE_object_copy_softbody(ob_dst, ob_src);
/* TODO: smoke?, cloth? */
}
@@ -342,7 +351,7 @@ void BKE_object_free_caches(Object *object)
psys = psys->next)
{
psys_free_path_cache(psys, psys->edit);
- update_flag |= PSYS_RECALC;
+ update_flag |= PSYS_RECALC_REDO;
}
}
@@ -354,6 +363,7 @@ void BKE_object_free_caches(Object *object)
psmd->dm->needsFree = 1;
psmd->dm->release(psmd->dm);
psmd->dm = NULL;
+ psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
}
}
@@ -408,7 +418,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
ob->iuser = NULL;
if (ob->bb) MEM_freeN(ob->bb);
ob->bb = NULL;
- if (ob->adt) BKE_free_animdata((ID *)ob);
+ if (ob->adt) BKE_animdata_free((ID *)ob);
if (ob->poselib) ob->poselib->id.us--;
if (ob->gpd) ((ID *)ob->gpd)->us--;
if (ob->defbase.first)
@@ -434,7 +444,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->bsoft) bsbFree(ob->bsoft);
if (ob->gpulamp.first) GPU_lamp_free(ob);
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
@@ -531,7 +541,7 @@ void BKE_object_unlink(Object *ob)
bPoseChannel *pchan;
for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -562,7 +572,7 @@ void BKE_object_unlink(Object *ob)
sca_remove_ob_poin(obt, ob);
for (con = obt->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -808,34 +818,11 @@ void BKE_object_unlink(Object *ob)
}
}
}
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == (ID *)ob) tselem->id = NULL;
- }
- }
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
-
- if (sbuts->pinid == (ID *)ob) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- sbuts->pinid = NULL;
- }
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
-
- if (snode->from == (ID *)ob) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
+#if 0
+ else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
+ /* now handled by WM_main_remove_editor_id_reference */
}
+#endif
}
sa = sa->next;
@@ -938,26 +925,6 @@ bool BKE_object_exists_check(Object *obtest)
/* *************************************************** */
-void *BKE_object_obdata_add_from_type(Main *bmain, int type)
-{
- switch (type) {
- case OB_MESH: return BKE_mesh_add(bmain, "Mesh");
- case OB_CURVE: return BKE_curve_add(bmain, "Curve", OB_CURVE);
- case OB_SURF: return BKE_curve_add(bmain, "Surf", OB_SURF);
- case OB_FONT: return BKE_curve_add(bmain, "Text", OB_FONT);
- case OB_MBALL: return BKE_mball_add(bmain, "Meta");
- case OB_CAMERA: return BKE_camera_add(bmain, "Camera");
- case OB_LAMP: return BKE_lamp_add(bmain, "Lamp");
- case OB_LATTICE: return BKE_lattice_add(bmain, "Lattice");
- case OB_ARMATURE: return BKE_armature_add(bmain, "Armature");
- case OB_SPEAKER: return BKE_speaker_add(bmain, "Speaker");
- case OB_EMPTY: return NULL;
- default:
- printf("BKE_object_obdata_add_from_type: Internal error, bad type: %d\n", type);
- return NULL;
- }
-}
-
static const char *get_obdata_defname(int type)
{
switch (type) {
@@ -978,6 +945,30 @@ static const char *get_obdata_defname(int type)
}
}
+void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
+{
+ if (name == NULL) {
+ name = get_obdata_defname(type);
+ }
+
+ switch (type) {
+ case OB_MESH: return BKE_mesh_add(bmain, name);
+ case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE);
+ case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF);
+ case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT);
+ case OB_MBALL: return BKE_mball_add(bmain, name);
+ case OB_CAMERA: return BKE_camera_add(bmain, name);
+ case OB_LAMP: return BKE_lamp_add(bmain, name);
+ case OB_LATTICE: return BKE_lattice_add(bmain, name);
+ case OB_ARMATURE: return BKE_armature_add(bmain, name);
+ case OB_SPEAKER: return BKE_speaker_add(bmain, name);
+ case OB_EMPTY: return NULL;
+ default:
+ printf("%s: Internal error, bad type: %d\n", __func__, type);
+ return NULL;
+ }
+}
+
/* more general add: creates minimum required data, but without vertices etc. */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
@@ -1048,7 +1039,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob->jump_speed = 10.0f;
ob->fall_speed = 55.0f;
ob->col_group = 0x01;
- ob->col_mask = 0xff;
+ ob->col_mask = 0xffff;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -1063,16 +1054,16 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
/* general add: to scene, with layer from area and default name */
/* creates minimum required data, but without vertices etc. */
-Object *BKE_object_add(Main *bmain, Scene *scene, int type)
+Object *BKE_object_add(
+ Main *bmain, Scene *scene,
+ int type, const char *name)
{
Object *ob;
Base *base;
- char name[MAX_ID_NAME];
- BLI_strncpy(name, get_obdata_defname(type), sizeof(name));
ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = BKE_object_obdata_add_from_type(bmain, type);
+ ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
ob->lay = scene->lay;
@@ -1098,10 +1089,12 @@ void BKE_object_lod_add(Object *ob)
BLI_addtail(&ob->lodlevels, base);
base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
base->source = ob;
+ base->obhysteresis = 10;
last = ob->currentlod = base;
}
lod->distance = last->distance + 25.0f;
+ lod->obhysteresis = 10;
lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
BLI_addtail(&ob->lodlevels, lod);
@@ -1217,7 +1210,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
#endif /* WITH_GAMEENGINE */
-SoftBody *copy_softbody(SoftBody *sb, bool copy_caches)
+SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
{
SoftBody *sbn;
@@ -1341,24 +1334,24 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
return psysn;
}
-void BKE_object_copy_particlesystems(Object *obn, Object *ob)
+void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
{
ParticleSystem *psys, *npsys;
ModifierData *md;
- if (obn->type != OB_MESH) {
+ if (ob_dst->type != OB_MESH) {
/* currently only mesh objects can have soft body */
return;
}
- BLI_listbase_clear(&obn->particlesystem);
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ BLI_listbase_clear(&ob_dst->particlesystem);
+ for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
npsys = BKE_object_copy_particlesystem(psys);
- BLI_addtail(&obn->particlesystem, npsys);
+ BLI_addtail(&ob_dst->particlesystem, npsys);
/* need to update particle modifiers too */
- for (md = obn->modifiers.first; md; md = md->next) {
+ for (md = ob_dst->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->psys == psys)
@@ -1386,10 +1379,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob)
}
}
-void BKE_object_copy_softbody(Object *obn, Object *ob)
+void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
{
- if (ob->soft)
- obn->soft = copy_softbody(ob->soft, false);
+ if (ob_src->soft) {
+ ob_dst->softflag = ob_src->softflag;
+ ob_dst->soft = copy_softbody(ob_src->soft, false);
+ }
}
static void copy_object_pose(Object *obn, Object *ob)
@@ -1406,7 +1401,7 @@ static void copy_object_pose(Object *obn, Object *ob)
chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
for (con = chan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1614,7 +1609,7 @@ void BKE_object_make_local(Object *ob)
if (ob->id.lib == NULL) return;
- ob->proxy = ob->proxy_from = NULL;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
if (ob->id.us == 1) {
id_clear_lib_data(bmain, &ob->id);
@@ -1705,7 +1700,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* add new animdata block */
if (!ob->adt)
- ob->adt = BKE_id_add_animdata(&ob->id);
+ ob->adt = BKE_animdata_add_id(&ob->id);
/* make a copy of all the drivers (for now), then correct any links that need fixing */
free_fcurves(&ob->adt->drivers);
@@ -1767,8 +1762,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
if (gob->dup_group) { /* should always be true */
float tvec[3];
- copy_v3_v3(tvec, gob->dup_group->dupli_ofs);
- mul_mat3_m4_v3(ob->obmat, tvec);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -2063,14 +2057,12 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4])
add_v3_v3v3(mat[3], ob->loc, ob->dloc);
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]);
-
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
{
if (ob->parent) {
float par_imat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -2090,7 +2082,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
unit_m4(mat);
cu = par->data;
- if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */
+ if (par->curve_cache == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
BKE_displist_make_curveTypes(scene, par, 0);
if (par->curve_cache->path == NULL) return;
@@ -2125,7 +2117,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
/* vec: 4 items! */
- if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) {
+ if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
if (cu->flag & CU_FOLLOW) {
#if 0
@@ -2219,7 +2211,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
md != NULL;
md = md->next)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
/* TODO(sergey): Check for disabled modifiers. */
if (mti->type != eModifierTypeType_OnlyDeform && md->next != NULL) {
use_special_ss_case = false;
@@ -2362,7 +2354,8 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+
+void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -2419,7 +2412,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- ob_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2577,7 +2570,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
if (use_parent && ob->parent) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
invert_m4_m4(imat, diff_mat);
@@ -3012,8 +3005,12 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
{
if (ob->recalc & OB_RECALC_ALL) {
/* speed optimization for animation lookups */
- if (ob->pose)
+ if (ob->pose) {
BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+ }
if (ob->recalc & OB_RECALC_DATA) {
if (ob->type == OB_ARMATURE) {
@@ -3039,8 +3036,9 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
Object *obg = ob->proxy_from->proxy_group;
- invert_m4_m4(obg->imat, obg->obmat);
- mul_m4_m4m4(ob->obmat, obg->imat, ob->proxy_from->obmat);
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
if (obg->dup_group) { /* should always be true */
add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
}
@@ -3053,147 +3051,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
}
if (ob->recalc & OB_RECALC_DATA) {
- ID *data_id = (ID *)ob->data;
- AnimData *adt = BKE_animdata_from_id(data_id);
- Key *key;
- float ctime = BKE_scene_frame_get(scene);
-
- if (G.debug & G_DEBUG_DEPSGRAPH)
- printf("recalcdata %s\n", ob->id.name + 2);
-
- if (adt) {
- /* evaluate drivers - datalevel */
- /* XXX: for mesh types, should we push this to derivedmesh instead? */
- BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- key = BKE_key_from_object(ob);
- if (key && key->block.first) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK))
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* includes all keys and modifiers */
- switch (ob->type) {
- case OB_MESH:
- {
- BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
- uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
-#ifdef WITH_FREESTYLE
- /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
- data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
- }
-#endif
- if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(scene, ob, NULL, data_mask, 0);
- }
- break;
- }
- case OB_ARMATURE:
- if (ob->id.lib && ob->proxy_from) {
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
- }
- else {
- BKE_pose_where_is(scene, ob);
- }
- break;
-
- case OB_MBALL:
- BKE_displist_make_mball(eval_ctx, scene, ob);
- break;
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
- break;
-
- case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
- break;
-
- case OB_EMPTY:
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
- if (BKE_image_is_animated(ob->data))
- BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
- break;
- }
-
- /* related materials */
- /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
- * However, not doing anything (or trying to hack around this lack) is not an option
- * anymore, especially due to Cycles [#31834]
- */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
-
- if (ma) {
- /* recursively update drivers for this material */
- material_drivers_update(scene, ma, ctime);
- }
- }
- }
- else if (ob->type == OB_LAMP)
- lamp_drivers_update(scene, ob->data, ctime);
-
- /* particles */
- if (ob != scene->obedit && ob->particlesystem.first) {
- ParticleSystem *tpsys, *psys;
- DerivedMesh *dm;
- ob->transflag &= ~OB_DUPLIPARTS;
-
- psys = ob->particlesystem.first;
- while (psys) {
- /* ensure this update always happens even if psys is disabled */
- if (psys->recalc & PSYS_RECALC_TYPE) {
- psys_changed_type(ob, psys);
- }
-
- if (psys_check_enabled(ob, psys)) {
- /* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
- ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
- (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
- {
- ob->transflag |= OB_DUPLIPARTS;
- }
-
- particle_system_update(scene, ob, psys);
- psys = psys->next;
- }
- else if (psys->flag & PSYS_DELETE) {
- tpsys = psys->next;
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- psys = tpsys;
- }
- else
- psys = psys->next;
- }
-
- if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
- }
-
- /* quick cache removed */
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
}
ob->recalc &= ~OB_RECALC_ALL;
@@ -3238,7 +3096,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
ss->pbvh = NULL;
}
- BKE_free_sculptsession_deformMats(ob->sculpt);
+ BKE_sculptsession_free_deformMats(ob->sculpt);
}
else {
PBVHNode **nodes;
@@ -3501,7 +3359,7 @@ static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_m
return kb;
}
-KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix)
+KeyBlock *BKE_object_shapekey_insert(Object *ob, const char *name, const bool from_mix)
{
switch (ob->type) {
case OB_MESH:
@@ -3517,6 +3375,85 @@ KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool f
}
+bool BKE_object_shapekey_free(Main *bmain, Object *ob)
+{
+ Key **key_p, *key;
+
+ key_p = BKE_key_from_object_p(ob);
+ if (ELEM(NULL, key_p, *key_p)) {
+ return false;
+ }
+
+ key = *key_p;
+ *key_p = NULL;
+
+ BKE_libblock_free_us(bmain, key);
+
+ return false;
+}
+
+bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
+{
+ KeyBlock *rkb;
+ Key *key = BKE_key_from_object(ob);
+ short kb_index;
+
+ if (key == NULL) {
+ return false;
+ }
+
+ kb_index = BLI_findindex(&key->block, kb);
+ BLI_assert(kb_index != -1);
+
+ for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ if (rkb->relative == kb_index) {
+ /* remap to the 'Basis' */
+ rkb->relative = 0;
+ }
+ else if (rkb->relative >= kb_index) {
+ /* Fix positional shift of the keys when kb is deleted from the list */
+ rkb->relative -= 1;
+ }
+ }
+
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+ if (key->refkey == kb) {
+ key->refkey = key->block.first;
+
+ if (key->refkey) {
+ /* apply new basis key on original data */
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
+ break;
+ case OB_LATTICE:
+ BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
+ break;
+ }
+ }
+ }
+
+ if (kb->data) {
+ MEM_freeN(kb->data);
+ }
+ MEM_freeN(kb);
+
+ if (ob->shapenr > 1) {
+ ob->shapenr--;
+ }
+
+ if (key->totkey == 0) {
+ BKE_object_shapekey_free(bmain, ob);
+ }
+
+ return true;
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -3668,7 +3605,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool can_deform = mti->type == eModifierTypeType_OnlyDeform ||
is_modifier_animated;
@@ -3725,7 +3662,7 @@ void BKE_object_relink(Object *ob)
modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
if (ob->adt)
- BKE_relink_animdata(ob->adt);
+ BKE_animdata_relink(ob->adt);
if (ob->rigidbody_constraint)
BKE_rigidbody_relink_constraint(ob->rigidbody_constraint);
@@ -4038,3 +3975,51 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot)
*r_tot = tot;
return tree;
}
+
+bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
+{
+ if (modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO: this should be handled as part of build_animdata() -- Aligorith */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 10];
+ /* TODO(sergey): Escape modifier name. */
+ BLI_snprintf(pattern, sizeof(pattern), "modifiers[%s", md->name);
+
+ /* action - check for F-Curves with paths containing 'modifiers[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly
+ *
+ * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
+ * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
+ * by the RNA updates cache introduced in r.38649
+ */
+ for (fcu = (FCurve *)adt->drivers.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+
+ /* XXX: also, should check NLA strips, though for now assume that nobody uses
+ * that and we can omit that for performance reasons... */
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index e46929dde4a..f6e939a103e 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -163,7 +163,7 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
/**
* Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
@@ -241,7 +241,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
/**
* Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index c77f65f69e1..8abe4bdbb97 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -1237,7 +1237,7 @@ int count_duplilist(Object *ob)
return 1;
}
-DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
+DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
{
DupliApplyData *apply_data = NULL;
int num_objects = BLI_listbase_count(duplilist);
@@ -1253,6 +1253,13 @@ DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
/* copy obmat from duplis */
copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
+
+ /* make sure derivedmesh is calculated once, before drawing */
+ if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
+ mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
+ dob->ob->transflag |= OB_DUPLICALCDERIVED;
+ }
+
copy_m4_m4(dob->ob->obmat, dob->mat);
/* copy layers from the main duplicator object */
@@ -1273,6 +1280,7 @@ void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data)
*/
for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) {
copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat);
+ dob->ob->transflag &= ~OB_DUPLICALCDERIVED;
dob->ob->lay = apply_data->extra[i].lay;
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
new file mode 100644
index 00000000000..483968c6bd9
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -0,0 +1,348 @@
+/*
+ * ***** 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) 20014 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_update.c
+ * \ingroup bke
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "BKE_global.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_animsys.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_key.h"
+#include "BKE_lamp.h"
+#include "BKE_lattice.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+#include "BKE_material.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
+
+void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* calculate local matrix */
+ BKE_object_to_mat4(ob, ob->obmat);
+}
+
+/* Evaluate parent */
+/* NOTE: based on solve_parenting(), but with the cruft stripped out */
+void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ Object *par = ob->parent;
+
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* get local matrix (but don't calculate it, as that was done already!) */
+ // XXX: redundant?
+ copy_m4_m4(locmat, ob->obmat);
+
+ /* get parent effect matrix */
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
+
+ /* total */
+ mul_m4_m4m4(tmat, totmat, ob->parentinv);
+ mul_m4_m4m4(ob->obmat, tmat, locmat);
+
+ /* origin, for help line */
+ if ((ob->partype & PARTYPE) == PARSKEL) {
+ copy_v3_v3(ob->orig, par->obmat[3]);
+ }
+ else {
+ copy_v3_v3(ob->orig, totmat[3]);
+ }
+}
+
+void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ bConstraintOb *cob;
+ float ctime = BKE_scene_frame_get(scene);
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* evaluate constraints stack */
+ /* TODO: split this into:
+ * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
+ * - inner body of BKE_constraints_solve),
+ * - post (i.e. BKE_constraints_clear_evalob)
+ *
+ * Not sure why, this is from Joshua - sergey
+ *
+ */
+ cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(&ob->constraints, cob, ctime);
+ BKE_constraints_clear_evalob(cob);
+}
+
+void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* Set negative scale flag in object. */
+ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
+ 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)
+{
+ ID *data_id = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(data_id);
+ Key *key;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH)
+ printf("recalcdata %s\n", ob->id.name + 2);
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ if (adt) {
+ /* evaluate drivers - datalevel */
+ /* XXX: for mesh types, should we push this to derivedmesh instead? */
+ BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
+ }
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ key = BKE_key_from_object(ob);
+ if (key && key->block.first) {
+ if (!(ob->shapeflag & OB_SHAPE_LOCK))
+ BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ }
+
+ /* includes all keys and modifiers */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
+ uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
+#ifdef WITH_FREESTYLE
+ /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
+ if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
+ data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ }
+#endif
+ if (em) {
+ makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(scene, ob, NULL, data_mask, 0);
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ if (ob->id.lib && ob->proxy_from) {
+ if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
+ printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
+ ob->id.name + 2, ob->proxy_from->id.name + 2);
+ }
+ }
+ else {
+ BKE_pose_where_is(scene, ob);
+ }
+ break;
+
+ case OB_MBALL:
+ BKE_displist_make_mball(eval_ctx, scene, ob);
+ break;
+
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ BKE_displist_make_curveTypes(scene, ob, 0);
+ break;
+
+ case OB_LATTICE:
+ BKE_lattice_modifiers_calc(scene, ob);
+ break;
+
+ case OB_EMPTY:
+ if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
+ if (BKE_image_is_animated(ob->data))
+ BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
+ break;
+ }
+
+ /* related materials */
+ /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
+ * However, not doing anything (or trying to hack around this lack) is not an option
+ * anymore, especially due to Cycles [#31834]
+ */
+ if (ob->totcol) {
+ int a;
+ if (ob->totcol != 0) {
+ BLI_mutex_lock(&material_lock);
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+ if (ma) {
+ /* recursively update drivers for this material */
+ material_drivers_update(scene, ma, ctime);
+ }
+ }
+ BLI_mutex_unlock(&material_lock);
+ }
+ }
+ else if (ob->type == OB_LAMP)
+ lamp_drivers_update(scene, ob->data, ctime);
+
+ /* particles */
+ if (ob != scene->obedit && ob->particlesystem.first) {
+ ParticleSystem *tpsys, *psys;
+ DerivedMesh *dm;
+ ob->transflag &= ~OB_DUPLIPARTS;
+ psys = ob->particlesystem.first;
+ while (psys) {
+ /* ensure this update always happens even if psys is disabled */
+ if (psys->recalc & PSYS_RECALC_TYPE) {
+ psys_changed_type(ob, psys);
+ }
+
+ if (psys_check_enabled(ob, psys)) {
+ /* check use of dupli objects here */
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
+ (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
+ {
+ ob->transflag |= OB_DUPLIPARTS;
+ }
+
+ particle_system_update(scene, ob, psys);
+ psys = psys->next;
+ }
+ else if (psys->flag & PSYS_DELETE) {
+ tpsys = psys->next;
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ psys = tpsys;
+ }
+ else
+ psys = psys->next;
+ }
+
+ if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
+ /* this is to make sure we get render level duplis in groups:
+ * the derivedmesh must be created before init_render_mesh,
+ * since object_duplilist does dupliparticles before that */
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ dm->release(dm);
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next)
+ psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+ }
+ }
+
+ /* quick cache removed */
+}
+
+void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */
+ // XXX: it's almost redundant now...
+
+ /* Handle proxy copy for target, */
+ if (ob->id.lib && ob->proxy_from) {
+ if (ob->proxy_from->proxy_group) {
+ /* Transform proxy into group space. */
+ Object *obg = ob->proxy_from->proxy_group;
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
+ /* Should always be true. */
+ if (obg->dup_group) {
+ add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
+ }
+ }
+ else
+ copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
+ }
+
+ ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
+ if (ob->data == NULL) {
+ ob->recalc &= ~OB_RECALC_DATA;
+ }
+}
+
+void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ BLI_assert(ob->type != OB_ARMATURE);
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
+
+ ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 12e82d3a34f..1a178fb2bdf 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -494,7 +494,7 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount)
+void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
int i, j;
@@ -732,14 +732,14 @@ static void set_height_normalize_factor(struct Ocean *oc)
oc->normalize_factor = 1.0;
- BKE_simulate_ocean(oc, 0.0, 1.0, 0);
+ BKE_ocean_simulate(oc, 0.0, 1.0, 0);
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
for (i = 0; i < oc->_M; ++i) {
for (j = 0; j < oc->_N; ++j) {
- if (max_h < fabsf(oc->_disp_y[i * oc->_N + j])) {
- max_h = fabsf(oc->_disp_y[i * oc->_N + j]);
+ if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
+ max_h = fabs(oc->_disp_y[i * oc->_N + j]);
}
}
}
@@ -754,7 +754,7 @@ static void set_height_normalize_factor(struct Ocean *oc)
oc->normalize_factor = res;
}
-struct Ocean *BKE_add_ocean(void)
+struct Ocean *BKE_ocean_add(void)
{
Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
@@ -763,7 +763,7 @@ struct Ocean *BKE_add_ocean(void)
return oc;
}
-void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
+void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals,
short do_jacobian, int seed)
{
@@ -900,7 +900,7 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V,
BLI_rng_free(rng);
}
-void BKE_free_ocean_data(struct Ocean *oc)
+void BKE_ocean_free_data(struct Ocean *oc)
{
if (!oc) return;
@@ -962,11 +962,11 @@ void BKE_free_ocean_data(struct Ocean *oc)
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-void BKE_free_ocean(struct Ocean *oc)
+void BKE_ocean_free(struct Ocean *oc)
{
if (!oc) return;
- BKE_free_ocean_data(oc);
+ BKE_ocean_free_data(oc);
BLI_rw_mutex_end(&oc->oceanmutex);
MEM_freeN(oc);
@@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase,
BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
- BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
+ BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
}
/* silly functions but useful to inline when the args do a lot of indirections */
@@ -1021,7 +1021,7 @@ MINLINE void value_to_rgba_unit_alpha(float r_rgba[4], const float value)
r_rgba[3] = 1.0f;
}
-void BKE_free_ocean_cache(struct OceanCache *och)
+void BKE_ocean_free_cache(struct OceanCache *och)
{
int i, f = 0;
@@ -1111,7 +1111,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in
}
}
-struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale,
+struct OceanCache *BKE_ocean_init_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale,
float chop_amount, float foam_coverage, float foam_fade, int resolution)
{
OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
@@ -1138,7 +1138,7 @@ struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbas
return och;
}
-void BKE_simulate_ocean_cache(struct OceanCache *och, int frame)
+void BKE_ocean_simulate_cache(struct OceanCache *och, int frame)
{
char string[FILE_MAX];
int f = frame;
@@ -1182,7 +1182,7 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame)
}
-void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel),
+void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
{
/* note: some of these values remain uninitialized unless certain options
@@ -1221,7 +1221,7 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
- BKE_simulate_ocean(o, och->time[i], och->wave_scale, och->chop_amount);
+ BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount);
/* add new foam */
for (y = 0; y < res_y; y++) {
@@ -1371,29 +1371,29 @@ void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr)
{
}
-void BKE_simulate_ocean(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount))
+void BKE_ocean_simulate(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount))
{
}
-struct Ocean *BKE_add_ocean(void)
+struct Ocean *BKE_ocean_add(void)
{
Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
return oc;
}
-void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz),
+void BKE_ocean_init(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz),
float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp),
float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field),
short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed))
{
}
-void BKE_free_ocean_data(struct Ocean *UNUSED(oc))
+void BKE_ocean_free_data(struct Ocean *UNUSED(oc))
{
}
-void BKE_free_ocean(struct Ocean *oc)
+void BKE_ocean_free(struct Ocean *oc)
{
if (!oc) return;
MEM_freeN(oc);
@@ -1403,7 +1403,7 @@ void BKE_free_ocean(struct Ocean *oc)
/* ********* Baking/Caching ********* */
-void BKE_free_ocean_cache(struct OceanCache *och)
+void BKE_ocean_free_cache(struct OceanCache *och)
{
if (!och) return;
@@ -1420,7 +1420,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult
{
}
-OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start),
+OceanCache *BKE_ocean_init_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start),
int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount),
float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution))
{
@@ -1429,11 +1429,11 @@ OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSE
return och;
}
-void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame))
+void BKE_ocean_simulate_cache(struct OceanCache *UNUSED(och), int UNUSED(frame))
{
}
-void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
+void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data))
{
/* unused */
diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 7700c2ff11e..f31ba34a984 100644
--- a/source/blender/blenkernel/intern/treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file treehash.c
+/** \file outliner_treehash.c
* \ingroup bke
*
* Tree hash for the outliner space.
@@ -28,7 +28,7 @@
#include <stdlib.h>
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -38,8 +38,7 @@
#include "MEM_guardedalloc.h"
-typedef struct TseGroup
-{
+typedef struct TseGroup {
TreeStoreElem **elems;
int size;
int allocated;
@@ -103,14 +102,17 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore)
TreeStoreElem *tselem;
BLI_mempool_iter iter;
BLI_mempool_iternew(treestore, &iter);
+
+ BLI_assert(treehash);
+
while ((tselem = BLI_mempool_iterstep(&iter))) {
- BKE_treehash_add_element(treehash, tselem);
+ BKE_outliner_treehash_add_element(treehash, tselem);
}
}
-void *BKE_treehash_create_from_treestore(BLI_mempool *treestore)
+void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore)
{
- GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore), false);
+ GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore));
fill_treehash(treehash, treestore);
return treehash;
}
@@ -120,35 +122,46 @@ static void free_treehash_group(void *key)
tse_group_free(key);
}
-void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
+void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
+ BLI_assert(treehash);
+
BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore));
fill_treehash(treehash, treestore);
return treehash;
}
-void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem)
+void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
{
- TseGroup *group = BLI_ghash_lookup(treehash, elem);
- if (!group) {
- group = tse_group_create();
- BLI_ghash_insert(treehash, elem, group);
+ TseGroup *group;
+ void **val_p;
+
+ if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) {
+ *val_p = tse_group_create();
}
+ group = *val_p;
tse_group_add(group, elem);
}
-static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
+static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
{
TreeStoreElem tse_template;
tse_template.type = type;
tse_template.nr = type ? nr : 0; // we're picky! :)
tse_template.id = id;
+
+ BLI_assert(th);
+
return BLI_ghash_lookup(th, &tse_template);
}
-TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
int i;
for (i = 0; i < group->size; i++) {
@@ -160,13 +173,19 @@ TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr,
return NULL;
}
-TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
return group ? group->elems[0] : NULL;
}
-void BKE_treehash_free(void *treehash)
+void BKE_outliner_treehash_free(void *treehash)
{
+ BLI_assert(treehash);
+
BLI_ghash_free(treehash, NULL, free_treehash_group);
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8d56b1247fe..800df252c69 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -128,8 +128,8 @@ int countPackedFiles(Main *bmain)
/* let's check if there are packed files... */
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
- count++;
+ if (BKE_image_has_packedfile(ima))
+ count ++;
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
if (vf->packedfile)
@@ -224,7 +224,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char
}
/* no libraries for now */
-void packAll(Main *bmain, ReportList *reports)
+void packAll(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
VFont *vfont;
@@ -232,12 +232,12 @@ void packAll(Main *bmain, ReportList *reports)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (ima->packedfile == NULL && ima->id.lib == NULL) {
+ if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
if (ima->source == IMA_SRC_FILE) {
- ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
- else if (BKE_image_is_animated(ima)) {
+ else if (BKE_image_is_animated(ima) && verbose) {
BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
ima->id.name + 2);
}
@@ -258,10 +258,10 @@ void packAll(Main *bmain, ReportList *reports)
}
}
- if (tot == 0)
- BKE_report(reports, RPT_INFO, "No new files have been packed");
- else
+ if (tot > 0)
BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ else if (verbose)
+ BKE_report(reports, RPT_INFO, "No new files have been packed");
}
@@ -478,7 +478,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
}
static void unpack_generate_paths(
- const char *name, ID *id, char *abspath_r, char *relpath_r, size_t abspathlen, size_t relpathlen)
+ const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen)
{
char tempname[FILE_MAX];
char tempdir[FILE_MAXDIR];
@@ -500,19 +500,19 @@ static void unpack_generate_paths(
switch (GS(id->name)) {
case ID_VF:
- BLI_snprintf(relpath_r, relpathlen, "//fonts/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
break;
case ID_SO:
- BLI_snprintf(relpath_r, relpathlen, "//sounds/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
break;
case ID_IM:
- BLI_snprintf(relpath_r, relpathlen, "//textures/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
break;
}
{
- size_t len = BLI_strncpy_rlen(abspath_r, tempdir, abspathlen);
- BLI_strncpy(abspath_r + len, tempname, abspathlen - len);
+ size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
+ BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
}
}
@@ -553,7 +553,7 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
ret_value = RET_OK;
}
@@ -564,23 +564,47 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
int unpackImage(ReportList *reports, Image *ima, int how)
{
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
int ret_value = RET_ERROR;
-
+
if (ima != NULL && ima->name[0]) {
- unpack_generate_paths(ima->name, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, absname, localname, ima->packedfile, how);
- if (newname != NULL) {
- ret_value = RET_OK;
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- BLI_strncpy(ima->name, newname, sizeof(ima->name));
- MEM_freeN(newname);
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ while (ima->packedfiles.last) {
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ ImagePackedFile *imapf = ima->packedfiles.last;
+
+ unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(reports, absname, localname, imapf->packedfile, how);
+
+ if (newname != NULL) {
+ ImageView *iv;
+
+ ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = NULL;
+
+ /* update the new corresponding view filepath */
+ iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
+ if (iv) {
+ BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
+ }
+
+ /* keep the new name in the image for non-pack specific reasons */
+ BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ MEM_freeN(newname);
+ }
+ else {
+ ret_value = RET_ERROR;
+ }
+
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
}
}
-
+
+ if (ret_value == RET_OK) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+
return(ret_value);
}
@@ -636,7 +660,7 @@ void unpackAll(Main *bmain, ReportList *reports, int how)
bSound *sound;
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
unpackImage(reports, ima, how);
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
@@ -655,7 +679,7 @@ bool BKE_pack_check(ID *id)
case ID_IM:
{
Image *ima = (Image *)id;
- return ima->packedfile != NULL;
+ return BKE_image_has_packedfile(ima);
}
case ID_VF:
{
@@ -683,7 +707,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
case ID_IM:
{
Image *ima = (Image *)id;
- if (ima->packedfile) {
+ if (BKE_image_has_packedfile(ima)) {
unpackImage(reports, ima, how);
}
break;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 431eec0d220..0bda740af53 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -313,25 +313,33 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
}
}
+void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index)
+{
+ pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
+}
+
/* remove colour from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
- if (color) {
- int numcolors = BLI_listbase_count(&palette->colors);
- if ((numcolors == palette->active_color + 1) && (numcolors != 1))
- palette->active_color--;
-
- BLI_remlink(&palette->colors, color);
- BLI_addhead(&palette->deleted, color);
+ if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) {
+ palette->active_color--;
}
+
+ BLI_remlink(&palette->colors, color);
+
+ if (palette->active_color < 0 && !BLI_listbase_is_empty(&palette->colors)) {
+ palette->active_color = 0;
+ }
+
+ MEM_freeN(color);
}
-void BKE_palette_cleanup(Palette *palette)
+void BKE_palette_clear(Palette *palette)
{
- BLI_freelistN(&palette->deleted);
+ BLI_freelistN(&palette->colors);
+ palette->active_color = 0;
}
-
Palette *BKE_palette_add(Main *bmain, const char *name)
{
Palette *palette;
@@ -353,7 +361,6 @@ PaletteColor *BKE_palette_color_add(Palette *palette)
{
PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
BLI_addtail(&palette->colors, color);
- palette->active_color = BLI_listbase_count(&palette->colors) - 1;
return color;
}
@@ -512,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
/* threshold to move before updating the brush rotation */
#define RAKE_THRESHHOLD 20
-static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
+void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
{
if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
ups->brush_rotation = rotation;
@@ -520,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
ups->brush_rotation = 0.0f;
if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
- /* here, translation contains the mouse coordinates. */
ups->brush_rotation_sec = rotation;
else
ups->brush_rotation_sec = 0.0f;
@@ -529,7 +535,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
{
if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- const float u = 0.5f;
const float r = RAKE_THRESHHOLD;
float rotation;
@@ -539,17 +544,16 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
if (len_squared_v2(dpos) >= r * r) {
rotation = atan2f(dpos[0], dpos[1]);
- interp_v2_v2v2(ups->last_rake, ups->last_rake,
- mouse_pos, u);
+ copy_v2_v2(ups->last_rake, mouse_pos);
ups->last_rake_angle = rotation;
- update_brush_rake_rotation(ups, brush, rotation);
+ paint_update_brush_rake_rotation(ups, brush, rotation);
}
/* make sure we reset here to the last rotation to avoid accumulating
* values in case a random rotation is also added */
else {
- update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
+ paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
}
}
else {
@@ -557,15 +561,11 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
}
}
-void BKE_free_sculptsession_deformMats(SculptSession *ss)
+void BKE_sculptsession_free_deformMats(SculptSession *ss)
{
- if (ss->orig_cos) MEM_freeN(ss->orig_cos);
- if (ss->deform_cos) MEM_freeN(ss->deform_cos);
- if (ss->deform_imats) MEM_freeN(ss->deform_imats);
-
- ss->orig_cos = NULL;
- ss->deform_cos = NULL;
- ss->deform_imats = NULL;
+ MEM_SAFE_FREE(ss->orig_cos);
+ MEM_SAFE_FREE(ss->deform_cos);
+ MEM_SAFE_FREE(ss->deform_imats);
}
/* Write out the sculpt dynamic-topology BMesh to the Mesh */
@@ -624,7 +624,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
}
}
-void BKE_free_sculptsession(Object *ob)
+void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
@@ -718,7 +718,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) continue;
@@ -765,7 +765,12 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
/* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */
- BKE_mesh_tessface_ensure(me);
+ if (ss->bm) {
+ BKE_mesh_tessface_clear(me);
+ }
+ else {
+ BKE_mesh_tessface_ensure(me);
+ }
if (!mmd) ss->kb = BKE_keyblock_from_object(ob);
else ss->kb = NULL;
@@ -780,7 +785,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
- ss->face_normals = NULL;
}
else {
ss->totvert = me->totvert;
@@ -788,7 +792,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
- ss->face_normals = NULL;
ss->multires = NULL;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
@@ -802,7 +805,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
if (!ss->orig_cos) {
int a;
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
@@ -815,7 +818,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
else {
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
}
if (ss->kb != NULL && ss->deform_cos == NULL) {
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 291efd03a66..6c354c59d7a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -103,6 +103,8 @@ void psys_init_rng(void)
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
+static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
+ int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
extern void do_child_modifiers(ParticleSimulationData *sim,
ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
@@ -373,7 +375,7 @@ void BKE_particlesettings_free(ParticleSettings *part)
{
MTex *mtex;
int a;
- BKE_free_animdata(&part->id);
+ BKE_animdata_free(&part->id);
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
@@ -1943,9 +1945,11 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
void psys_find_parents(ParticleSimulationData *sim)
{
+ ParticleSystem *psys = sim->psys;
ParticleSettings *part = sim->psys->part;
KDTree *tree;
ChildParticle *cpa;
+ ParticleTexture ptex;
int p, totparent, totchild = sim->psys->totchild;
float co[3], orco[3];
int from = PART_FROM_FACE;
@@ -1963,7 +1967,13 @@ void psys_find_parents(ParticleSimulationData *sim)
for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
- BLI_kdtree_insert(tree, p, orco);
+
+ /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
+ get_cpa_texture(sim->psmd->dm, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+
+ if (ptex.exist >= psys_frand(psys, p + 24)) {
+ BLI_kdtree_insert(tree, p, orco);
+ }
}
BLI_kdtree_balance(tree);
@@ -1990,7 +2000,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys_in_edit_mode(scene, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2006,7 +2016,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
between = 1;
}
- if (psys->renderdata)
+ if (psys->renderdata || G.is_rendering)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2273,17 +2283,28 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
ParticleCacheKey *par = NULL;
float par_co[3];
float par_orco[3];
-
+
if (ctx->totparent) {
if (i >= ctx->totparent) {
pa = &psys->particles[cpa->parent];
/* this is now threadsafe, virtual parents are calculated before rest of children */
+ BLI_assert(cpa->parent < psys->totchildcache);
par = cache[cpa->parent];
}
}
else if (cpa->parent >= 0) {
pa = &psys->particles[cpa->parent];
par = pcache[cpa->parent];
+
+ /* If particle is unexisting, try to pick a viable parent from particles used for interpolation. */
+ for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
+ if (cpa->pa[k] >= 0) {
+ pa = &psys->particles[cpa->pa[k]];
+ par = pcache[cpa->pa[k]];
+ }
+ }
+
+ if (pa->flag & PARS_UNEXIST) pa = NULL;
}
if (pa) {
@@ -2315,6 +2336,7 @@ static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UN
cpa = psys->child + task->begin;
for (i = task->begin; i < task->end; ++i, ++cpa) {
+ BLI_assert(i < psys->totchildcache);
psys_thread_create_path(task, cpa, cache[i], i);
}
}
@@ -2353,7 +2375,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
/* cache parent paths */
ctx.parent_pass = 1;
- psys_tasks_create(&ctx, totparent, &tasks_parent, &numtasks_parent);
+ psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
for (i = 0; i < numtasks_parent; ++i) {
ParticleTask *task = &tasks_parent[i];
@@ -2364,7 +2386,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
/* cache child paths */
ctx.parent_pass = 0;
- psys_tasks_create(&ctx, totchild, &tasks_child, &numtasks_child);
+ psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
for (i = 0; i < numtasks_child; ++i) {
ParticleTask *task = &tasks_child[i];
@@ -2448,7 +2470,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 245c2432105..50634460028 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -332,7 +332,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount)
rng = BLI_rng_new(31415926 + num + seed2);
x= 0;
- num2 = 2 * num;
+ num2 = 2 * num;
for (i=0; i<num2; i+=2) {
jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
@@ -490,7 +490,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
DerivedMesh *dm= ctx->dm;
- float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3];
+ float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
int i, intersect, tot;
@@ -530,14 +530,12 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot=dm->getNumTessFaces(dm);
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
normalize_v3(nor);
- mul_v3_fl(nor,-100.0);
+ negate_v3(nor);
- add_v3_v3v3(co2,co1,nor);
-
- min_d=2.0;
+ min_d=FLT_MAX;
intersect=0;
for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
@@ -547,20 +545,20 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
v2=mvert[mface->v2].co;
v3=mvert[mface->v3].co;
- if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
if (mface->v4) {
v4=mvert[mface->v4].co;
- if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
@@ -668,6 +666,8 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U
ParticleSystem *psys= task->ctx->sim.psys;
ParticleData *pa;
int p;
+
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin);
pa= psys->particles + task->begin;
switch (psys->part->from) {
@@ -1121,7 +1121,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
task_pool = BLI_task_pool_create(task_scheduler, &ctx);
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
- psys_tasks_create(&ctx, totpart, &tasks, &numtasks);
+ psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
for (i = 0; i < numtasks; ++i) {
ParticleTask *task = &tasks[i];
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index b7ebcfa9b0b..3a19ca7304c 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -90,6 +90,7 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
+#include "BKE_depsgraph.h"
#include "PIL_time.h"
@@ -297,7 +298,7 @@ int psys_get_child_number(Scene *scene, ParticleSystem *psys)
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr);
+ return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
}
int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
@@ -448,24 +449,24 @@ BLI_INLINE int ceil_ii(int a, int b)
return (a + b - 1) / b;
}
-void psys_tasks_create(ParticleThreadContext *ctx, int totpart, ParticleTask **r_tasks, int *r_numtasks)
+void psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart, ParticleTask **r_tasks, int *r_numtasks)
{
ParticleTask *tasks;
- int numtasks = ceil_ii(totpart, MAX_PARTICLES_PER_TASK);
- float particles_per_task = (float)totpart / (float)numtasks, p, pnext;
+ int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK);
+ float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext;
int i;
tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
*r_numtasks = numtasks;
*r_tasks = tasks;
- p = 0.0f;
+ p = (float)startpart;
for (i = 0; i < numtasks; i++, p = pnext) {
pnext = p + particles_per_task;
tasks[i].ctx = ctx;
tasks[i].begin = (int)p;
- tasks[i].end = min_ii((int)pnext, totpart);
+ tasks[i].end = min_ii((int)pnext, endpart);
}
}
@@ -559,17 +560,24 @@ static void initialize_all_particles(ParticleSimulationData *sim)
ParticleSystem *psys = sim->psys;
PARTICLE_P;
+ LOOP_PARTICLES {
+ initialize_particle(sim, pa);
+ }
+}
+
+static void free_unexisting_particles(ParticleSimulationData *sim)
+{
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+
psys->totunexist = 0;
LOOP_PARTICLES {
- if ((pa->flag & PARS_UNEXIST)==0)
- initialize_particle(sim, pa);
-
- if (pa->flag & PARS_UNEXIST)
+ if (pa->flag & PARS_UNEXIST) {
psys->totunexist++;
+ }
}
- /* Free unexisting particles. */
if (psys->totpart && psys->totunexist == psys->totpart) {
if (psys->particles->boid)
MEM_freeN(psys->particles->boid);
@@ -3790,6 +3798,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
initialize_all_particles(sim);
/* reset only just created particles (on startframe all particles are recreated) */
reset_all_particles(sim, 0.0, cfra, oldtotpart);
+ free_unexisting_particles(sim);
if (psys->fluid_springs) {
MEM_freeN(psys->fluid_springs);
@@ -4136,6 +4145,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
{
PARTICLE_P;
float disp = psys_get_current_display_percentage(psys);
+ bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
if (psys->recalc & PSYS_RECALC_RESET)
@@ -4145,6 +4155,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
free_keyed_keys(psys);
distribute_particles(&sim, part->from);
initialize_all_particles(&sim);
+ free_unexisting = true;
/* flag for possible explode modifiers after this system */
sim.psmd->flag |= eParticleSystemFlag_Pars;
@@ -4163,6 +4174,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
pa->flag &= ~PARS_NO_DISP;
}
+ /* free unexisting after reseting particles */
+ if (free_unexisting)
+ free_unexisting_particles(&sim);
+
if (part->phystype == PART_PHYS_KEYED) {
psys_count_keyed_targets(&sim);
set_keyed_keys(&sim);
@@ -4195,3 +4210,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
invert_m4_m4(psys->imat, ob->obmat);
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ ParticleSystem *psys)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s:%s\n", __func__, ob->id.name, psys->name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 5e07437d426..95d8e37d1c7 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -232,16 +232,11 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi)
void pbvh_grow_nodes(PBVH *bvh, int totnode)
{
- if (totnode > bvh->node_mem_count) {
- PBVHNode *prev = bvh->nodes;
- bvh->node_mem_count *= 1.33;
+ if (UNLIKELY(totnode > bvh->node_mem_count)) {
+ bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
if (bvh->node_mem_count < totnode)
bvh->node_mem_count = totnode;
- bvh->nodes = MEM_mallocN(sizeof(PBVHNode) * bvh->node_mem_count,
- "bvh nodes");
- memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode));
- memset(bvh->nodes + bvh->totnode, 0, (bvh->node_mem_count - bvh->totnode) * sizeof(PBVHNode));
- MEM_freeN(prev);
+ bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
}
bvh->totnode = totnode;
@@ -575,7 +570,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
+void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
BBC *prim_bbc = NULL;
@@ -585,7 +580,6 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
bvh->type = PBVH_GRIDS;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
bvh->grid_flag_mats = flagmats;
bvh->totgrid = totgrid;
@@ -699,16 +693,16 @@ static void pbvh_iter_end(PBVHIter *iter)
static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting)
{
- if (iter->stacksize == iter->stackspace) {
- PBVHStack *newstack;
-
+ if (UNLIKELY(iter->stacksize == iter->stackspace)) {
iter->stackspace *= 2;
- newstack = MEM_callocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
- memcpy(newstack, iter->stack, sizeof(PBVHStack) * iter->stacksize);
- if (iter->stackspace > STACK_FIXED_DEPTH)
- MEM_freeN(iter->stack);
- iter->stack = newstack;
+ if (iter->stackspace != STACK_FIXED_DEPTH) {
+ iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
+ }
+ else {
+ iter->stack = MEM_mallocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
+ memcpy(iter->stack, iter->stackfixed, sizeof(PBVHStack) * iter->stacksize);
+ }
}
iter->stack[iter->stacksize].node = node;
@@ -800,7 +794,7 @@ void BKE_pbvh_search_gather(PBVH *bvh,
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
- if (tot == space) {
+ if (UNLIKELY(tot == space)) {
/* resize array if needed */
space = (tot == 0) ? 32 : space * 2;
array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
@@ -948,6 +942,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
int n;
if (bvh->type == PBVH_BMESH) {
+ BLI_assert(face_nors == NULL);
pbvh_bmesh_normals_update(nodes, totnode);
return;
}
@@ -1285,6 +1280,16 @@ PBVHType BKE_pbvh_type(const PBVH *bvh)
return bvh->type;
}
+bool BKE_pbvh_has_faces(const PBVH *bvh)
+{
+ if (bvh->type == PBVH_BMESH) {
+ return (bvh->bm->totface != 0);
+ }
+ else {
+ return (bvh->totprim != 0);
+ }
+}
+
void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
{
if (bvh->totnode) {
@@ -1377,7 +1382,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
-void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj)
+void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata)
{
switch (bvh->type) {
case PBVH_GRIDS:
@@ -1386,7 +1391,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = bvh->totgrid;
if (gridsize) *gridsize = bvh->gridkey.grid_size;
if (griddata) *griddata = bvh->grids;
- if (gridadj) *gridadj = bvh->gridadj;
break;
case PBVH_FACES:
case PBVH_BMESH:
@@ -1395,7 +1399,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = 0;
if (gridsize) *gridsize = 0;
if (griddata) *griddata = NULL;
- if (gridadj) *gridadj = NULL;
break;
}
}
@@ -1424,6 +1427,15 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
}
}
+void BKE_pbvh_node_get_bm_orco_data(
+ PBVHNode *node,
+ int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3])
+{
+ *r_orco_tris = node->bm_ortri;
+ *r_orco_tris_num = node->bm_tot_ortri;
+ *r_orco_coords = node->bm_orco;
+}
+
/********************************* Raycast ***********************************/
typedef struct {
@@ -1597,7 +1609,9 @@ bool BKE_pbvh_node_raycast(
return hit;
}
-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_raycast_project_ray_root(
+ PBVH *bvh, bool original,
+ float ray_start[3], float ray_end[3], float ray_normal[3])
{
if (bvh->nodes) {
float rootmin_start, rootmin_end;
@@ -1770,13 +1784,12 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
pbvh_draw_BB(bvh);
}
-void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces,
+void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
int a;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
@@ -1955,7 +1968,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->fno = NULL;
vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL);
+ BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
vi->key = &bvh->gridkey;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 01bca44d3b6..9f092bd651f 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_heap.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BKE_ccg.h"
#include "BKE_DerivedMesh.h"
@@ -41,6 +42,27 @@
#include <assert.h>
+/* Avoid skinny faces */
+#define USE_EDGEQUEUE_EVEN_SUBDIV
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+# include "BKE_global.h"
+#endif
+
+/* Support for only operating on front-faces */
+#define USE_EDGEQUEUE_FRONTFACE
+
+/* don't add edges into the queue multiple times */
+#define USE_EDGEQUEUE_TAG
+/**
+ * Ensure we don't have dirty tags for the edge queue, and that they are left cleared.
+ * (slow, even for debug mode, so leave disabled for now).
+ */
+#if defined(USE_EDGEQUEUE_TAG) && 0
+# if !defined(NDEBUG)
+# define USE_EDGEQUEUE_TAG_VERIFY
+# endif
+#endif
+
// #define USE_VERIFY
#ifdef USE_VERIFY
@@ -107,7 +129,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
}
/* Recursively split the node if it exceeds the leaf_limit */
-static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
+static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
{
GSet *empty, *other;
GSetIterator gs_iter;
@@ -129,7 +151,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
BB_reset(&cb);
GSET_ITER (gs_iter, n->bm_faces) {
const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = BLI_ghash_lookup(prim_bbc, f);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
BB_expand(&cb, bbc->bcentroid);
}
@@ -157,7 +179,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Partition the parent node's faces between the two children */
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = BLI_ghash_lookup(prim_bbc, f);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
if (bbc->bcentroid[axis] < mid)
BLI_gset_insert(c1->bm_faces, f);
@@ -221,8 +243,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Recurse */
c1 = c2 = NULL;
- pbvh_bmesh_node_split(bvh, prim_bbc, children);
- pbvh_bmesh_node_split(bvh, prim_bbc, children + 1);
+ pbvh_bmesh_node_split(bvh, bbc_array, children);
+ pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
/* Array maybe reallocated, update current node pointer */
n = &bvh->nodes[node_index];
@@ -237,7 +259,6 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Recursively split the node if it exceeds the leaf_limit */
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
{
- GHash *prim_bbc;
GSet *bm_faces;
int bm_faces_size;
GSetIterator gs_iter;
@@ -252,8 +273,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
}
/* For each BMFace, store the AABB and AABB centroid */
- prim_bbc = BLI_ghash_ptr_new_ex("prim_bbc", bm_faces_size);
- bbc_array = MEM_callocN(sizeof(BBC) * bm_faces_size, "BBC");
+ bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
GSET_ITER_INDEX (gs_iter, bm_faces, i) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
@@ -268,12 +288,14 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
} while ((l_iter = l_iter->next) != l_first);
BBC_update_centroid(bbc);
- BLI_ghash_insert(prim_bbc, f, bbc);
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
}
+ /* likely this is already dirty */
+ bvh->bm->elem_index_dirty |= BM_FACE;
- pbvh_bmesh_node_split(bvh, prim_bbc, node_index);
+ pbvh_bmesh_node_split(bvh, bbc_array, node_index);
- BLI_ghash_free(prim_bbc, NULL, NULL);
MEM_freeN(bbc_array);
return true;
@@ -321,15 +343,21 @@ static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
static BMVert *pbvh_bmesh_vert_create(
PBVH *bvh, int node_index,
- const float co[3],
- const BMVert *example,
+ const float co[3], const float no[3],
const int cd_vert_mask_offset)
{
- BMVert *v = BM_vert_create(bvh->bm, co, example, BM_CREATE_NOP);
PBVHNode *node = &bvh->nodes[node_index];
+ BMVert *v;
BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
+ /* avoid initializing customdata because its quite involved */
+ v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
+
+ /* This value is logged below */
+ copy_v3_v3(v->no, no);
+
BLI_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
@@ -352,7 +380,7 @@ static BMFace *pbvh_bmesh_face_create(
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -369,6 +397,7 @@ static BMFace *pbvh_bmesh_face_create(
}
/* Return the number of faces in 'node' that use vertex 'v' */
+#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
BMIter bm_iter;
@@ -376,12 +405,33 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
int count = 0;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node;
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ if (f_node == node) {
+ count++;
+ }
+ }
- f_node = pbvh_bmesh_node_lookup(bvh, f);
+ return count;
+}
+#endif
+
+#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
+ (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n)
- if (f_node == node)
+static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
+{
+ BMIter bm_iter;
+ BMFace *f;
+ int count = 0;
+
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ if (f_node == node) {
count++;
+ if (count == count_max) {
+ break;
+ }
+ }
}
return count;
@@ -484,13 +534,13 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
v = l_iter->v;
- if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) {
+ if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
- BLI_assert(new_node || BM_vert_face_count(v) == 1);
+ BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
@@ -548,6 +598,15 @@ typedef struct {
const float *center;
float radius_squared;
float limit_len_squared;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ float limit_len;
+#endif
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ const float *view_normal;
+ unsigned int use_view_normal : 1;
+#endif
+
} EdgeQueue;
typedef struct {
@@ -559,6 +618,44 @@ typedef struct {
int cd_face_node_offset;
} EdgeQueueContext;
+/* only tag'd edges are in the queue */
+#ifdef USE_EDGEQUEUE_TAG
+# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG))
+# define EDGE_QUEUE_ENABLE(e) BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+# define EDGE_QUEUE_DISABLE(e) BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+/* simply check no edges are tagged
+ * (it's a requirement that edges enter and leave a clean tag state) */
+static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
+{
+ int n;
+
+ for (n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+ GSetIterator gs_iter;
+ if (node->bm_faces) {
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMEdge *e_tri[3];
+ BMLoop *l_iter;
+
+ BLI_assert(f->len == 3);
+ l_iter = BM_FACE_FIRST_LOOP(f);
+ e_tri[0] = l_iter->e; l_iter = l_iter->next;
+ e_tri[1] = l_iter->e; l_iter = l_iter->next;
+ e_tri[2] = l_iter->e;
+
+ BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) &&
+ (EDGE_QUEUE_TEST(e_tri[1]) == false) &&
+ (EDGE_QUEUE_TEST(e_tri[2]) == false));
+ }
+ }
+ }
+}
+#endif
+
static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
{
BMVert *v_tri[3];
@@ -580,8 +677,9 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f);
}
-static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
- float priority)
+static void edge_queue_insert(
+ EdgeQueueContext *eq_ctx, BMEdge *e,
+ float priority)
{
BMVert **pair;
@@ -600,28 +698,120 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
pair[0] = e->v1;
pair[1] = e->v2;
BLI_heap_insert(eq_ctx->q->heap, priority, pair);
+#ifdef USE_EDGEQUEUE_TAG
+ BLI_assert(EDGE_QUEUE_TEST(e) == false);
+ EDGE_QUEUE_ENABLE(e);
+#endif
}
}
-static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void long_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq > eq_ctx->q->limit_len_squared)
- edge_queue_insert(eq_ctx, e, -len_sq);
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(e) == false)
+#endif
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, -len_sq);
+ }
+ }
}
-static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+static void long_edge_queue_edge_add_recursive(
+ EdgeQueueContext *eq_ctx,
+ BMLoop *l_edge, BMLoop *l_end,
+ const float len_sq, float limit_len)
{
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq < eq_ctx->q->limit_len_squared)
- edge_queue_insert(eq_ctx, e, len_sq);
+ BLI_assert(len_sq > SQUARE(limit_len));
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(l_edge->e) == false)
+#endif
+ {
+ edge_queue_insert(eq_ctx, l_edge->e, -len_sq);
+ }
+
+ /* temp support previous behavior! */
+ if (UNLIKELY(G.debug_value == 1234)) {
+ return;
+ }
+
+ if ((l_edge->radial_next != l_edge)) {
+ /* how much longer we need to be to consider for subdividing
+ * (avoids subdividing faces which are only *slightly* skinny) */
+#define EVEN_EDGELEN_THRESHOLD 1.2f
+ /* how much the limit increases per recursion
+ * (avoids performing subdvisions too far away) */
+#define EVEN_GENERATION_SCALE 1.6f
+
+ const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
+ float limit_len_sq;
+ BMLoop *l_iter;
+
+ limit_len *= EVEN_GENERATION_SCALE;
+ limit_len_sq = SQUARE(limit_len);
+
+ l_iter = l_edge;
+ do {
+ float len_sq_other;
+ BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
+ int i;
+ for (i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
+ len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
+ if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
+// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i],
+ len_sq_other, limit_len);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+
+#undef EVEN_EDGELEN_THRESHOLD
+#undef EVEN_GENERATION_SCALE
+ }
}
+#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
-static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(e) == false)
+#endif
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq < eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, len_sq);
+ }
+ }
+}
+
+static void long_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
+{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -629,14 +819,34 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
/* Check each edge of the face */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ {
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_iter->radial_next, l_iter,
+ len_sq, eq_ctx->q->limit_len);
+ }
+#else
+ long_edge_queue_edge_add(eq_ctx, l_iter->e);
+#endif
+ }
} while ((l_iter = l_iter->next) != l_first);
}
}
-static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -658,9 +868,10 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the longest edge.
*/
-static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void long_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -668,6 +879,21 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ 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);
+#else
+ UNUSED_VARS(view_normal);
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+ pbvh_bmesh_edge_tag_verify(bvh);
+#endif
+
for (n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -698,9 +924,10 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the shortest edge.
*/
-static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void short_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -708,6 +935,16 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ 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);
+#else
+ UNUSED_VARS(view_normal);
+#endif
for (n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -738,21 +975,24 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
}
-static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BMEdge *e, BLI_Buffer *edge_loops)
+static void pbvh_bmesh_split_edge(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BMEdge *e, BLI_Buffer *edge_loops)
{
BMVert *v_new;
- float mid[3];
+ float co_mid[3], no_mid[3];
int i, node_index;
/* Get all faces adjacent to the edge */
pbvh_bmesh_edge_loops(edge_loops, e);
/* Create a new vertex in current node at the edge's midpoint */
- mid_v3_v3v3(mid, e->v1->co, e->v2->co);
+ mid_v3_v3v3(co_mid, e->v1->co, e->v2->co);
+ mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
+ normalize_v3(no_mid);
node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
- v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1, eq_ctx->cd_vert_mask_offset);
+ v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -788,6 +1028,32 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
if (ni != node_index && i == 0)
pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
+ /**
+ * The 2 new faces created and assigned to ``f_new`` have their
+ * verts & edges shuffled around.
+ *
+ * - faces wind anticlockwise in this example.
+ * - original edge is ``(v1, v2)``
+ * - oroginal face is ``(v1, v2, v3)``
+ *
+ * <pre>
+ * + v3(v_opp)
+ * /|\
+ * / | \
+ * / | \
+ * e4/ | \ e3
+ * / |e5 \
+ * / | \
+ * / e1 | e2 \
+ * +-------+-------+
+ * v1 v4(v_new) v2
+ * (first) (second)
+ * </pre>
+ *
+ * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)``
+ * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)``
+ */
+
/* Create two new faces */
v_tri[0] = v1;
v_tri[1] = v_new;
@@ -810,13 +1076,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_face_kill(bvh->bm, f_adj);
/* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new) &&
- !BLI_gset_haskey(bvh->nodes[ni].bm_other_verts, v_new))
- {
- BLI_gset_insert(bvh->nodes[ni].bm_other_verts, v_new);
+ if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
}
- if (BM_vert_edge_count(v_opp) >= 9) {
+ if (BM_vert_edge_count_is_over(v_opp, 8)) {
BMIter bm_iter;
BMEdge *e2;
@@ -829,8 +1093,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_edge_kill(bvh->bm, e);
}
-static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BLI_Buffer *edge_loops)
+static bool pbvh_bmesh_subdivide_long_edges(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
@@ -842,13 +1107,22 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
- if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
- continue;
-
/* Check that the edge still exists */
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
+#ifdef USE_EDGEQUEUE_TAG
+ EDGE_QUEUE_DISABLE(e);
+#endif
+
+ /* At the moment edges never get shorter (subdiv will make new edges)
+ * unlike collapse where edges can become longer. */
+#if 0
+ if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
+ continue;
+#else
+ BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared);
+#endif
/* Check that the edge's vertices are still in the PBVH. It's
* possible that an edge collapse has deleted adjacent faces
@@ -865,6 +1139,10 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
}
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+ pbvh_bmesh_edge_tag_verify(bvh);
+#endif
+
return any_subdivided;
}
@@ -945,10 +1223,8 @@ static void pbvh_bmesh_collapse_edge(
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
- if (!BLI_gset_haskey(n->bm_unique_verts, v_conn) &&
- !BLI_gset_haskey(n->bm_other_verts, v_conn))
- {
- BLI_gset_insert(n->bm_other_verts, v_conn);
+ if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
+ BLI_gset_add(n->bm_other_verts, v_conn);
}
}
@@ -970,18 +1246,6 @@ static void pbvh_bmesh_collapse_edge(
v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next;
v_tri[2] = l_iter->v; e_tri[2] = l_iter->e;
- /* Check if any of the face's vertices are now unused, if so
- * remove them from the PBVH */
- for (j = 0; j < 3; j++) {
- if (v_tri[j] != v_del && BM_vert_face_count(v_tri[j]) == 1) {
- BLI_gset_insert(deleted_verts, v_tri[j]);
- pbvh_bmesh_vert_remove(bvh, v_tri[j]);
- }
- else {
- v_tri[j] = NULL;
- }
- }
-
/* Remove the face */
pbvh_bmesh_face_remove(bvh, f_del);
BM_face_kill(bvh->bm, f_del);
@@ -993,9 +1257,13 @@ static void pbvh_bmesh_collapse_edge(
BM_edge_kill(bvh->bm, e_tri[j]);
}
- /* Delete unused vertices */
+ /* Check if any of the face's vertices are now unused, if so
+ * remove them from the PBVH */
for (j = 0; j < 3; j++) {
- if (v_tri[j]) {
+ if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
+ BLI_gset_insert(deleted_verts, v_tri[j]);
+ pbvh_bmesh_vert_remove(bvh, v_tri[j]);
+
BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
BM_vert_kill(bvh->bm, v_tri[j]);
}
@@ -1007,10 +1275,12 @@ static void pbvh_bmesh_collapse_edge(
if (!BLI_gset_haskey(deleted_verts, v_conn)) {
BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
+ add_v3_v3(v_conn->no, v_del->no);
+ normalize_v3(v_conn->no);
}
/* Delete v_del */
- BLI_assert(BM_vert_face_count(v_del) == 0);
+ BLI_assert(!BM_vert_face_check(v_del));
BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
BM_vert_kill(bvh->bm, v_del);
@@ -1042,13 +1312,16 @@ static bool pbvh_bmesh_collapse_short_edges(
continue;
}
- if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
- continue;
-
/* Check that the edge still exists */
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
+#ifdef USE_EDGEQUEUE_TAG
+ EDGE_QUEUE_DISABLE(e);
+#endif
+
+ if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
+ continue;
/* Check that the edge's vertices are still in the PBVH. It's
* possible that an edge collapse has deleted adjacent faces
@@ -1074,9 +1347,10 @@ static bool pbvh_bmesh_collapse_short_edges(
/************************* Called from pbvh.c *************************/
-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_raycast(
+ PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *dist,
+ bool use_original)
{
bool hit = false;
@@ -1189,36 +1463,225 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-/***************************** Public API *****************************/
+typedef struct FastNodeBuildInfo {
+ int totface; /* number of faces */
+ int start; /* start of faces in array */
+ struct FastNodeBuildInfo *child1;
+ struct FastNodeBuildInfo *child2;
+} FastNodeBuildInfo;
-static void pbvh_bmesh_node_layers_reset(PBVH *bvh)
+/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays */
+static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
{
BMFace *f;
- BMVert *v;
- BMIter iter;
- BMesh *bm = bvh->bm;
- int cd_vert_node_offset = bvh->cd_vert_node_offset;
- int cd_face_node_offset = bvh->cd_face_node_offset;
+ BB cb;
+ BBC *bbc;
+ float mid;
+ int axis, i;
+ int end;
+ FastNodeBuildInfo *child1, *child2;
+ int num_child1, num_child2;
+ BMFace *tmp;
- /* clear the elements of the node information */
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ if (node->totface <= bvh->leaf_limit) {
+ return;
}
- BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ /* Calculate bounding box around primitive centroids */
+ BB_reset(&cb);
+ for (i = 0; i < node->totface; i++) {
+ f = nodeinfo[i + node->start];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ /* initialize the children */
+
+ /* Find widest axis and its midpoint */
+ axis = BB_widest_axis(&cb);
+ mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ num_child1 = 0, num_child2 = 0;
+
+ /* split vertices along the middle line */
+ end = node->start + node->totface;
+ for (i = node->start; i < end - num_child2; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ if (bbc->bcentroid[axis] > mid) {
+ int i_iter = end - num_child2 - 1;
+ int candidate = -1;
+ /* found a face that should be part of another node, look for a face to substitute with */
+
+ for (;i_iter > i; i_iter--) {
+ BMFace *f_iter = nodeinfo[i_iter];
+ const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)];
+ if (bbc_iter->bcentroid[axis] <= mid) {
+ candidate = i_iter;
+ break;
+ }
+ else {
+ num_child2++;
+ }
+ }
+
+ if (candidate != -1) {
+ tmp = nodeinfo[i];
+ nodeinfo[i] = nodeinfo[candidate];
+ nodeinfo[candidate] = tmp;
+ /* increase both counts */
+ num_child1++;
+ num_child2++;
+ }
+ else {
+ /* not finding candidate means second half of array part is full of
+ * second node parts, just increase the number of child nodes for it */
+ num_child2++;
+ }
+ }
+ else {
+ num_child1++;
+ }
+ }
+
+ /* ensure at least one child in each node */
+ if (num_child2 == 0) {
+ num_child2++;
+ num_child1--;
+ }
+ else if (num_child1 == 0) {
+ num_child1++;
+ num_child2--;
+ }
+
+ /* at this point, faces should have been split along the array range sequentially,
+ * each sequential part belonging to one node only */
+ BLI_assert((num_child1 + num_child2) == node->totface);
+
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+
+ child1->totface = num_child1;
+ child1->start = node->start;
+ child2->totface = num_child2;
+ child2->start = node->start + num_child1;
+ child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
+
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+
+ return;
+}
+
+static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+{
+ PBVHNode *n = bvh->nodes + node_index;
+ /* two cases, node does not have children or does have children */
+ if (node->child1) {
+ int children_offset = bvh->totnode;
+
+ n->children_offset = children_offset;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+
+ n = &bvh->nodes[node_index];
+
+ /* Update bounding box */
+ BB_reset(&n->vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ n->orig_vb = n->vb;
+ }
+ else {
+ /* node does not have children so it's a leaf node, populate with faces and tag accordingly
+ * this is an expensive part but it's not so easily threadable due to vertex node indices */
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+
+ bool has_visible = false;
+ int i, end;
+ BMFace *f;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMVert *v;
+ BBC *bbc;
+
+ n->flag = PBVH_Leaf;
+ n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
+
+ /* Create vert hash sets */
+ n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
+ n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+
+ BB_reset(&n->vb);
+
+ end = node->start + node->totface;
+
+ for (i = node->start; i < end; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ /* Update ownership of faces */
+ BLI_gset_insert(n->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+
+ /* Update vertices */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ v = l_iter->v;
+ if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_add(n->bm_other_verts, v);
+ }
+ else {
+ BLI_gset_insert(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ }
+ }
+ /* Update node bounding box */
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ has_visible = true;
+
+ BB_expand_with_bb(&n->vb, (BB *)bbc);
+ }
+
+ BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
+ n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
+
+ n->orig_vb = n->vb;
+
+ /* Build GPU buffers for new node and update vertex normals */
+ BKE_pbvh_node_mark_rebuild_draw(n);
+
+ BKE_pbvh_node_fully_hidden_set(n, !has_visible);
+ n->flag |= PBVH_UpdateNormals;
}
}
+/***************************** Public API *****************************/
+
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
- const int cd_vert_node_offset, const int cd_face_node_offset)
+void BKE_pbvh_build_bmesh(
+ PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
BMIter iter;
BMFace *f;
- PBVHNode *n;
- int node_index = 0;
+ BMVert *v;
+ int i;
+ /* bounding box array of all faces, no need to recalculate every time */
+ BBC *bbc_array;
+ BMFace **nodeinfo;
+ FastNodeBuildInfo rootnode = {0};
+ MemArena *arena;
bvh->cd_vert_node_offset = cd_vert_node_offset;
bvh->cd_face_node_offset = cd_face_node_offset;
@@ -1235,26 +1698,61 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
if (smooth_shading)
bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
- pbvh_bmesh_node_layers_reset(bvh);
+ /* calculate all bounding boxes once for all faces */
+ bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+ nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+
+ BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BBC *bbc = &bbc_array[i];
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ BB_reset((BB *)bbc);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BB_expand((BB *)bbc, l_iter->v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+ BBC_update_centroid(bbc);
+
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
+ nodeinfo[i] = f;
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ /* likely this is already dirty */
+ bm->elem_index_dirty |= BM_FACE;
+
+ /* setup root node */
+ rootnode.totface = bm->totface;
+
+ /* start recursion, assign faces to nodes accordingly */
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+
+ /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
/* Start with all faces in the root node */
- n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
bvh->totnode = 1;
- n->flag = PBVH_Leaf;
- n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", bvh->bm->totface);
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(n->bm_faces, f);
- }
- /* Recursively split the node until it is under the limit; if no
- * splitting occurs then finalize the existing leaf node */
- if (!pbvh_bmesh_node_limit_ensure(bvh, node_index))
- pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset);
+ /* take root node and visit and populate children recursively */
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+
+ BLI_memarena_free(arena);
+ MEM_freeN(bbc_array);
+ MEM_freeN(nodeinfo);
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], float radius)
+bool BKE_pbvh_bmesh_update_topology(
+ PBVH *bvh, PBVHTopologyUpdateMode mode,
+ const float center[3], const float view_normal[3],
+ float radius)
{
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
@@ -1266,12 +1764,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
bool modified = false;
int n;
+ if (view_normal) {
+ BLI_assert(len_squared_v3(view_normal) != 0.0f);
+ }
+
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- short_edge_queue_create(&eq_ctx, bvh, center, radius);
+ short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
&deleted_faces);
@@ -1284,7 +1786,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- long_edge_queue_create(&eq_ctx, bvh, center, radius);
+ long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
@@ -1641,7 +2143,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(BM_vert_face_count(v) > 0);
+ BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 6b3ef8eb5da..7daccb47c92 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -139,7 +139,6 @@ struct PBVH {
/* Grid Data */
CCGKey gridkey;
CCGElem **grids;
- DMGridAdjacency *gridadj;
void **gridfaces;
const DMFlagMat *grid_flag_mats;
int totgrid;
@@ -175,9 +174,10 @@ void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
-bool ray_face_intersection(const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2,
- const float *t3, float *fdist);
+bool ray_face_intersection(
+ const float ray_start[3], const float ray_normal[3],
+ const float *t0, const float *t1, const float *t2,
+ const float *t3, float *fdist);
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index c477aabbb71..2f4a45828ea 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3093,7 +3093,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data)
}
/* returns first point cache */
-PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data)
+PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data)
{
PointCache *cache = ptcaches_old->first;
@@ -3354,7 +3354,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
- BLI_end_threads(&threads);
+ BLI_end_threads(&threads);
}
/* clear baking flag */
if (pid) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index aaf54b82f32..ff9e1a2b831 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -54,6 +54,7 @@
#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -61,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
#ifdef WITH_BULLET
@@ -1610,3 +1612,51 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif
#endif /* WITH_BULLET */
+
+/* -------------------- */
+/* Depsgraph evaluation */
+
+void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* rebuild sim data (i.e. after resetting to start of timeline) */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_rebuild_world(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* evaluate rigidbody sim */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_do_simulation(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, ob->id.name);
+ }
+
+ /* read values pushed into RBO from sim/cache... */
+ BKE_rigidbody_sync_transforms(rbw, ob, ctime);
+}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f94f7cd8f0b..28c94c889a2 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -75,6 +75,7 @@
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_node.h"
@@ -82,16 +83,20 @@
#include "BKE_paint.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RE_engine.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
#include "bmesh.h"
@@ -153,18 +158,21 @@ Scene *BKE_scene_copy(Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
+ FreestyleLineSet *lineset;
ToolSettings *ts;
Base *base, *obase;
if (type == SCE_COPY_EMPTY) {
- ListBase lb;
+ ListBase rl, rv;
/* XXX. main should become an arg */
scen = BKE_scene_add(G.main, sce->id.name + 2);
- lb = scen->r.layers;
+ rl = scen->r.layers;
+ rv = scen->r.views;
scen->r = sce->r;
- scen->r.layers = lb;
+ 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;
@@ -187,6 +195,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->ed = NULL;
scen->theDag = NULL;
+ scen->depsgraph = NULL;
scen->obedit = NULL;
scen->stats = NULL;
scen->fps_info = NULL;
@@ -197,6 +206,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
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) {
@@ -224,7 +234,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
sizeof(scen->sequencer_colorspace_settings.name));
/* copy action and remove animation used by sequencer */
- BKE_copy_animdata_id_action(&scen->id);
+ BKE_animdata_copy_id_action(&scen->id);
if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen);
@@ -233,6 +243,14 @@ Scene *BKE_scene_copy(Scene *sce, int type)
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(G.main, lineset->linestyle);
+ }
+ }
+ }
new_srl = new_srl->next;
}
}
@@ -293,14 +311,14 @@ Scene *BKE_scene_copy(Scene *sce, int type)
}
/* before scene copy */
- sound_create_scene(scen);
+ 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(scen->world);
- BKE_copy_animdata_id_action((ID *)scen->world);
+ BKE_animdata_copy_id_action((ID *)scen->world);
}
if (sce->ed) {
@@ -361,7 +379,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->base);
BKE_sequencer_editing_free(sce);
- BKE_free_animdata((ID *)sce);
+ BKE_animdata_free((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
if (sce->rigidbody_world)
@@ -390,6 +408,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
+ BLI_freelistN(&sce->r.views);
if (sce->toolsettings) {
if (sce->toolsettings->vpaint) {
@@ -415,6 +434,8 @@ void BKE_scene_free(Scene *sce)
}
DAG_scene_free(sce);
+ if (sce->depsgraph)
+ DEG_graph_free(sce->depsgraph);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -426,7 +447,7 @@ void BKE_scene_free(Scene *sce)
if (sce->fps_info)
MEM_freeN(sce->fps_info);
- sound_destroy_scene(sce);
+ BKE_sound_destroy_scene(sce);
BKE_color_managed_view_settings_free(&sce->view_settings);
}
@@ -437,6 +458,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
ParticleEditSettings *pset;
int a;
const char *colorspace_name;
+ SceneRenderView *srv;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
sce->lay = sce->layact = 1;
@@ -628,7 +650,16 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
BKE_scene_add_render_layer(sce, NULL);
-
+
+ /* multiview - stereo */
+ BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
+ srv = sce->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
+ srv = sce->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
/* game data */
sce->gm.stereoflag = STEREO_NOSTEREO;
sce->gm.stereomode = STEREO_ANAGLYPH;
@@ -665,7 +696,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->gm.recastData.cellsize = 0.3f;
sce->gm.recastData.cellheight = 0.2f;
- sce->gm.recastData.agentmaxslope = M_PI / 2;
+ sce->gm.recastData.agentmaxslope = M_PI_4;
sce->gm.recastData.agentmaxclimb = 0.9f;
sce->gm.recastData.agentheight = 2.0f;
sce->gm.recastData.agentradius = 0.6f;
@@ -677,9 +708,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->gm.recastData.detailsampledist = 6.0f;
sce->gm.recastData.detailsamplemaxerror = 1.0f;
+ sce->gm.lodflag = SCE_LOD_USE_HYST;
+ sce->gm.scehysteresis = 10;
+
sce->gm.exitkey = 218; // Blender key code for ESC
- sound_create_scene(sce);
+ BKE_sound_create_scene(sce);
/* color management */
colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
@@ -698,6 +732,19 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
+Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+{
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ break;
+ }
+ }
+
+ return base;
+}
+
Base *BKE_scene_base_find(Scene *scene, Object *ob)
{
return BLI_findptr(&scene->base, ob, offsetof(Base, object));
@@ -767,33 +814,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-static void scene_unlink_space_node(SpaceNode *snode, Scene *sce)
-{
- if (snode->id == &sce->id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
-}
-
-static void scene_unlink_space_buts(SpaceButs *sbuts, Scene *sce)
-{
- if (sbuts->pinid == &sce->id) {
- sbuts->pinid = NULL;
- }
-}
-
void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
{
Scene *sce1;
@@ -818,24 +838,11 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
/* all screens */
for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
-
- if (screen->scene == sce)
+ if (screen->scene == sce) {
screen->scene = newsce;
-
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
- switch (space_link->spacetype) {
- case SPACE_NODE:
- scene_unlink_space_node((SpaceNode *)space_link, sce);
- break;
- case SPACE_BUTS:
- scene_unlink_space_buts((SpaceButs *)space_link, sce);
- break;
- }
- }
}
+
+ /* editors are handled by WM_main_remove_editor_id_reference */
}
BKE_libblock_free(bmain, sce);
@@ -1140,13 +1147,13 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
/* This function is needed to cope with fractional frames - including two Blender rendering features
* mblur (motion blur that renders 'subframes' and blurs them together), and fields rendering.
*/
-float BKE_scene_frame_get(Scene *scene)
+float BKE_scene_frame_get(const Scene *scene)
{
return BKE_scene_frame_get_from_ctime(scene, scene->r.cfra);
}
/* This function is used to obtain arbitrary fractional frames */
-float BKE_scene_frame_get_from_ctime(Scene *scene, const float frame)
+float BKE_scene_frame_get_from_ctime(const Scene *scene, const float frame)
{
float ctime = frame;
ctime += scene->r.subframe;
@@ -1165,6 +1172,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
+#ifdef WITH_LEGACY_DEPSGRAPH
/* drivers support/hacks
* - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
* - these are always run since the depsgraph can't handle non-object data
@@ -1265,6 +1273,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
}
}
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
@@ -1294,6 +1303,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain)
}
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
{
if (scene->set)
@@ -1311,12 +1321,18 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
if (BKE_scene_check_rigidbody_active(scene))
BKE_rigidbody_do_simulation(scene, ctime);
}
+#endif
/* Used to visualize CPU threads activity during threaded object update,
* would pollute STDERR with whole bunch of timing information which then
* could be parsed and nicely visualized.
*/
-#undef DETAILED_ANALYSIS_OUTPUT
+#ifdef WITH_LEGACY_DEPSGRAPH
+# undef DETAILED_ANALYSIS_OUTPUT
+#else
+/* ALWAYS KEEY DISABLED! */
+# undef DETAILED_ANALYSIS_OUTPUT
+#endif
/* Mballs evaluation uses BKE_scene_base_iter_next which calls
* duplilist for all objects in the scene. This leads to conflict
@@ -1328,6 +1344,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
+#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
Object *object;
@@ -1342,13 +1359,13 @@ typedef struct ThreadedObjectUpdateState {
Scene *scene_parent;
double base_time;
- /* Execution statistics */
- ListBase statistics[BLENDER_MAX_THREADS];
- bool has_updated_objects;
-
#ifdef MBALL_SINGLETHREAD_HACK
bool has_mballs;
#endif
+
+ /* Execution statistics */
+ bool has_updated_objects;
+ ListBase *statistics;
} ThreadedObjectUpdateState;
static void scene_update_object_add_task(void *node, void *user_data);
@@ -1417,6 +1434,8 @@ static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadi
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;
@@ -1446,6 +1465,7 @@ static void scene_update_object_add_task(void *node, void *user_data)
static void print_threads_statistics(ThreadedObjectUpdateState *state)
{
int i, tot_thread;
+ double finish_time;
if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) {
return;
@@ -1471,6 +1491,7 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
}
}
#else
+ finish_time = PIL_check_seconds_timer();
tot_thread = BLI_system_thread_count();
for (i = 0; i < tot_thread; i++) {
@@ -1500,6 +1521,9 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
BLI_freelistN(&state->statistics[i]);
}
+ if (state->has_updated_objects) {
+ printf("Scene update in %f sec\n", finish_time - state->base_time);
+ }
#endif
}
@@ -1545,7 +1569,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
/* Those are only needed when blender is run with --debug argument. */
if (G.debug & G_DEBUG_DEPSGRAPH) {
- memset(state.statistics, 0, sizeof(state.statistics));
+ const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
+ "scene update objects stats");
state.has_updated_objects = false;
state.base_time = PIL_check_seconds_timer();
}
@@ -1555,6 +1581,9 @@ 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);
@@ -1562,6 +1591,7 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
if (G.debug & G_DEBUG_DEPSGRAPH) {
print_threads_statistics(&state);
+ MEM_freeN(state.statistics);
}
/* We do single thread pass to update all the objects which are in cyclic dependency.
@@ -1607,6 +1637,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
BKE_mask_update_scene(bmain, scene);
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
@@ -1658,13 +1689,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#endif
+
/* keep this first */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
/* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
+ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
DAG_scene_relations_update(bmain, sce_iter);
+ /* Uncomment this to check if graph was properly tagged for update. */
+#if 0
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval)
+#endif
+ {
+ DAG_scene_relations_validate(bmain, sce_iter);
+ }
+#endif
+ }
/* flush editing data if needed */
prepare_mesh_for_viewport_render(bmain, scene);
@@ -1685,9 +1729,20 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* in the future this should handle updates for all datablocks, not
* only objects and scenes. - brecht */
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+ }
+ else
+#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) */
- sound_update_scene(bmain, scene);
+ BKE_sound_update_scene(bmain, scene);
/* extra call here to recalc scene animation (for sequencer) */
{
@@ -1703,7 +1758,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
* Need to do this so changing material settings from the graph/dopesheet
* will update stuff in the viewport.
*/
- if (DAG_id_type_tagged(bmain, ID_MA)) {
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
Material *material;
float ctime = BKE_scene_frame_get(scene);
@@ -1718,7 +1774,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
/* Also do the same for node trees. */
- if (DAG_id_type_tagged(bmain, ID_NT)) {
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
float ctime = BKE_scene_frame_get(scene);
FOREACH_NODETREE(bmain, ntree, id)
@@ -1729,9 +1785,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
FOREACH_NODETREE_END
}
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
+
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
@@ -1751,6 +1810,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#ifdef DETAILED_ANALYSIS_OUTPUT
double start_time = PIL_check_seconds_timer();
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#else
+ /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
+ (void) do_invisible_flush;
+#endif
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1760,13 +1825,17 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* call this at the start so modifiers with textures don't lag 1 frame */
BKE_image_update_frame(bmain, sce->r.cfra);
+#ifdef WITH_LEGACY_DEPSGRAPH
/* rebuild rigid body worlds before doing the actual frame update
* this needs to be done on start frame but animation playback usually starts one frame later
* we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
*/
- scene_rebuild_rbw_recursive(sce, ctime);
-
- sound_set_cfra(sce->r.cfra);
+ if (!use_new_eval) {
+ scene_rebuild_rbw_recursive(sce, ctime);
+ }
+#endif
+
+ BKE_sound_set_cfra(sce->r.cfra);
/* clear animation overrides */
/* XXX TODO... */
@@ -1774,14 +1843,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ /* flush recalc flags to dependencies, if we were only changing a frame
+ * this would not be necessary, but if a user or a script has modified
+ * some datablock before BKE_scene_update_tagged was called, we need the flush */
+ DAG_ids_flush_tagged(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
+ /* 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
+ }
+#endif
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@@ -1795,8 +1868,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* can be overridden by settings from Scene, which owns the Texture through a hierarchy
* such as Scene->World->MTex/Texture) can still get correctly overridden.
*/
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
+ /*...done with recursive funcs */
+ }
+#endif
/* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
@@ -1806,19 +1883,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
- scene_do_rb_simulation_recursive(sce, ctime);
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_do_rb_simulation_recursive(sce, ctime);
+ }
+#endif
+
/* BKE_object_handle_update() on all objects, groups and sets */
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+ }
+#else
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
- sound_update_scene(bmain, sce);
+ BKE_sound_update_scene(bmain, sce);
- scene_depsgraph_hack(eval_ctx, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_depsgraph_hack(eval_ctx, sce, sce);
+ }
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, sce, true);
/* clear recalc flags */
@@ -1889,25 +1985,71 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return true;
}
+/* return default view */
+SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
+{
+ SceneRenderView *srv;
+
+ if (!name)
+ name = DATA_("RenderView");
+
+ srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
+ BLI_strncpy(srv->name, name, sizeof(srv->name));
+ BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name));
+ BLI_addtail(&sce->r.views, srv);
+
+ return srv;
+}
+
+bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
+{
+ const int act = BLI_findindex(&scene->r.views, srv);
+
+ if (act == -1) {
+ return false;
+ }
+ else if (scene->r.views.first == scene->r.views.last) {
+ /* ensure 1 view is kept */
+ return false;
+ }
+
+ BLI_remlink(&scene->r.views, srv);
+ MEM_freeN(srv);
+
+ scene->r.actview = 0;
+
+ return true;
+}
+
/* render simplification */
-int get_render_subsurf_level(RenderData *r, int lvl)
+int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return min_ii(r->simplify_subsurf, lvl);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return min_ii(r->simplify_subsurf_render, lvl);
+ else
+ return min_ii(r->simplify_subsurf, lvl);
+ }
+ else {
return lvl;
+ }
}
-int get_render_child_particle_number(RenderData *r, int num)
+int get_render_child_particle_number(const RenderData *r, int num, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return (int)(r->simplify_particles * num);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return (int)(r->simplify_particles_render * num);
+ else
+ return (int)(r->simplify_particles * num);
+ }
+ else {
return num;
+ }
}
-int get_render_shadow_samples(RenderData *r, int samples)
+int get_render_shadow_samples(const RenderData *r, int samples)
{
if ((r->mode & R_SIMPLIFY) && samples > 0)
return min_ii(r->simplify_shadowsamples, samples);
@@ -1915,7 +2057,7 @@ int get_render_shadow_samples(RenderData *r, int samples)
return samples;
}
-float get_render_aosss_error(RenderData *r, float error)
+float get_render_aosss_error(const RenderData *r, float error)
{
if (r->mode & R_SIMPLIFY)
return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error;
@@ -1947,18 +2089,24 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
return NULL;
}
-bool BKE_scene_use_new_shading_nodes(Scene *scene)
+bool BKE_scene_use_new_shading_nodes(const Scene *scene)
{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
+ const RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SHADING_NODES);
}
-bool BKE_scene_uses_blender_internal(struct Scene *scene)
+bool BKE_scene_use_shading_nodes_custom(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+}
+
+bool BKE_scene_uses_blender_internal(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
}
-bool BKE_scene_uses_blender_game(struct Scene *scene)
+bool BKE_scene_uses_blender_game(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
}
@@ -2059,3 +2207,284 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
return value;
}
}
+
+/******************** multiview *************************/
+
+size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
+{
+ SceneRenderView *srv;
+ size_t totviews = 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+
+ srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ else {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ }
+ return totviews;
+}
+
+bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
+{
+ SceneRenderView *srv[2];
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+
+ return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) &&
+ srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
+}
+
+/* return whether to render this SceneRenderView */
+bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
+{
+ if (srv == NULL)
+ return false;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ return false;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return true;
+
+ /* SCE_VIEWS_SETUP_BASIC */
+ if (STREQ(srv->name, STEREO_LEFT_NAME) ||
+ STREQ(srv->name, STEREO_RIGHT_NAME))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* return true if viewname is the first or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+/* return true if viewname is the last or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.last; srv; srv = srv->prev) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return NULL;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (nr++ == view_id)
+ return srv;
+ }
+ }
+ return srv;
+}
+
+const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
+
+ if (srv)
+ return srv->name;
+ else
+ return "";
+}
+
+size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
+ return 0;
+
+ if ((!viewname) || (!viewname[0]))
+ return 0;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (STREQ(viewname, srv->name)) {
+ return nr;
+ }
+ else {
+ nr += 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void BKE_scene_multiview_filepath_get(
+ SceneRenderView *srv, const char *filepath,
+ char *r_filepath)
+{
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
+}
+
+/**
+ * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``).
+ * When multiview is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
+ * individual views.
+ */
+void BKE_scene_multiview_view_filepath_get(
+ const RenderData *rd, const char *filepath, const char *viewname,
+ char *r_filepath)
+{
+ SceneRenderView *srv;
+ char suffix[FILE_MAX];
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
+ else
+ BLI_strncpy(suffix, viewname, sizeof(suffix));
+
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
+}
+
+const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((viewname == NULL) || (viewname[0] == '\0'))
+ return viewname;
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ return srv->suffix;
+ else
+ return viewname;
+}
+
+const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id)
+{
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ return "";
+ }
+ else {
+ const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
+ return BKE_scene_multiview_view_suffix_get(rd, viewname);
+ }
+}
+
+void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, const char **rext)
+{
+ SceneRenderView *srv;
+ size_t index_act;
+ const char *suf_act;
+ const char delims[] = {'.', '\0'};
+
+ rprefix[0] = '\0';
+
+ /* begin of extension */
+ index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
+ BLI_assert(index_act > 0);
+ UNUSED_VARS_NDEBUG(index_act);
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ size_t len = strlen(srv->suffix);
+ if (STREQLEN(*rext - len, srv->suffix, len)) {
+ BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_scene_multiview_videos_dimensions_get(
+ const RenderData *rd, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ if ((rd->scemode & R_MULTIVIEW) &&
+ rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D)
+ {
+ IMB_stereo3d_write_dimensions(
+ rd->im_format.stereo3d_format.display_mode,
+ (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
+ width, height,
+ r_width, r_height);
+ }
+ else {
+ *r_width = width;
+ *r_height = height;
+ }
+}
+
+size_t BKE_scene_multiview_num_videos_get(const RenderData *rd)
+{
+ if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
+ return 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ return BKE_scene_multiview_num_views_get(rd);
+ }
+}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index a6ac4551f4a..4125a35cb33 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -272,6 +272,19 @@ void BKE_spacedata_draw_locks(int set)
}
}
+static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+
+void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+{
+ spacedata_id_unref_cb = func;
+}
+
+void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+{
+ if (spacedata_id_unref_cb) {
+ spacedata_id_unref_cb(sl, id);
+ }
+}
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
@@ -405,6 +418,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa)
return NULL;
}
+ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+{
+ ARegion *ar_found = NULL;
+ if (sa) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
+ if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+ ar_found = ar;
+ break;
+ }
+ }
+ }
+ }
+ return ar_found;
+}
+
/**
* \note, ideally we can get the area from the context,
* there are a few places however where this isn't practical.
@@ -488,6 +518,23 @@ unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const stru
return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
}
+/**
+ * Accumulate all visible layers on this screen.
+ */
+unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
+{
+ const ScrArea *sa;
+ unsigned int lay = 0;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+ lay |= v3d->lay;
+ }
+ }
+
+ return lay;
+}
+
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
int bit;
@@ -510,8 +557,8 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
if ((v3d->lay & v3d->layact) == 0) {
for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 41f17665065..abfc858fd03 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
@@ -41,6 +42,7 @@
#include "BLI_listbase.h"
#include "BKE_sequencer.h"
+#include "BKE_scene.h"
typedef struct SeqCacheKey {
struct Sequence *seq;
@@ -77,7 +79,9 @@ static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
(a->bmain != b->bmain) ||
(a->scene != b->scene) ||
(a->motion_blur_shutter != b->motion_blur_shutter) ||
- (a->motion_blur_samples != b->motion_blur_samples));
+ (a->motion_blur_samples != b->motion_blur_samples) ||
+ (a->scene->r.views_format != b->scene->r.views_format) ||
+ (a->view_id != b->view_id));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
@@ -89,6 +93,7 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a)
rval ^= ((intptr_t) a->scene) << 6;
rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
rval ^= a->motion_blur_samples << 24;
+ rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 32;
return rval;
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 6157d63047e..f8608ce9406 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -52,9 +52,6 @@
#include "RNA_access.h"
-/* TODO(sergey): Could be considered a bad level call, but
- * need this for gaussian table.
- */
#include "RE_pipeline.h"
static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
@@ -2480,7 +2477,7 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
if ((seq->seq1->enddisp != seq->seq1->start) &&
(seq->seq1->len != 0))
{
- fallback_fac = (float) seq->seq1->len / (float) (seq->seq1->enddisp - seq->seq1->start);
+ fallback_fac = 1.0f;
flags = SEQ_SPEED_INTEGRATE;
fcu = NULL;
}
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index b78529f51b4..f543a9f4c65 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -77,9 +77,9 @@ typedef struct ModifierThread {
} ModifierThread;
-static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, bool make_float)
+static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float)
{
- return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, make_float);
+ return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float);
}
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -531,15 +531,11 @@ static void maskmodifier_apply_threaded(int width, int height, unsigned char *re
}
}
-static void maskmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
{
- BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd;
- BrightContrastThreadData data;
-
- data.bright = bcmd->bright;
- data.contrast = bcmd->contrast;
+ // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
- modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, &data);
+ modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
}
static SequenceModifierTypeInfo seqModifier_Mask = {
@@ -567,7 +563,7 @@ static void sequence_modifier_type_info_init(void)
#undef INIT_TYPE
}
-SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
+const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
{
if (!modifierTypesInit) {
sequence_modifier_type_info_init();
@@ -580,7 +576,7 @@ SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
{
SequenceModifierData *smd;
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
smd = MEM_callocN(smti->struct_size, "sequence modifier");
@@ -627,7 +623,7 @@ void BKE_sequence_modifier_clear(Sequence *seq)
void BKE_sequence_modifier_free(SequenceModifierData *smd)
{
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti && smti->free_data) {
smti->free_data(smd);
@@ -638,7 +634,7 @@ void BKE_sequence_modifier_free(SequenceModifierData *smd)
void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
{
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLF_I18NCONTEXT_ID_SEQUENCE, smti->name), '.',
offsetof(SequenceModifierData, name), sizeof(smd->name));
@@ -660,7 +656,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence
}
for (smd = seq->modifiers.first; smd; smd = smd->next) {
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
/* could happen if modifier is being removed or not exists in current version of blender */
if (!smti)
@@ -671,7 +667,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence
continue;
if (smti->apply) {
- ImBuf *mask = modifier_mask_get(smd, context, cfra, ibuf->rect_float != NULL);
+ ImBuf *mask = modifier_mask_get(smd, context, cfra, seq->start, ibuf->rect_float != NULL);
if (processed_ibuf == ibuf)
processed_ibuf = IMB_dupImBuf(ibuf);
@@ -696,7 +692,7 @@ void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
for (smd = seq->modifiers.first; smd; smd = smd->next) {
SequenceModifierData *smdn;
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
smdn = MEM_dupallocN(smd);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index cb23b1eb88e..4ec5dd58973 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -53,6 +53,12 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#else
+# include <unistd.h>
+#endif
+
#include "BLF_translation.h"
#include "BKE_animsys.h"
@@ -66,6 +72,7 @@
#include "BKE_scene.h"
#include "BKE_mask.h"
#include "BKE_library.h"
+#include "BKE_idprop.h"
#include "RNA_access.h"
@@ -88,6 +95,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview);
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id);
/* **** XXX ******** */
#define SELECT 1
@@ -180,10 +189,7 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
if (seq->strip)
seq_free_strip(seq->strip);
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
if (seq->type & SEQ_TYPE_EFFECT) {
struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
@@ -195,6 +201,10 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
((ID *)seq->sound)->us--;
}
+ if (seq->stereo3d_format) {
+ MEM_freeN(seq->stereo3d_format);
+ }
+
/* clipboard has no scene and will never have a sound handle or be active
* same goes to sequences copy for proxy rebuild job
*/
@@ -205,11 +215,16 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
ed->act_seq = NULL;
if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE))
- sound_remove_scene_sound(scene, seq->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq_free_animdata(scene, seq);
}
+ if (seq->prop) {
+ IDP_FreeProperty(seq->prop);
+ MEM_freeN(seq->prop);
+ }
+
/* free modifiers */
BKE_sequence_modifier_clear(seq);
@@ -234,6 +249,22 @@ void BKE_sequence_free(Scene *scene, Sequence *seq)
BKE_sequence_free_ex(scene, seq, true);
}
+/* Function to free imbuf and anim data on changes */
+void BKE_sequence_free_anim(Sequence *seq)
+{
+ while (seq->anims.last) {
+ StripAnim *sanim = seq->anims.last;
+
+ if (sanim->anim) {
+ IMB_free_anim(sanim->anim);
+ sanim->anim = NULL;
+ }
+
+ BLI_freelinkN(&seq->anims, sanim);
+ }
+ BLI_listbase_clear(&seq->anims);
+}
+
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
static void seq_free_sequence_recurse(Scene *scene, Sequence *seq)
@@ -316,7 +347,7 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
{
id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name));
if (id_restore == NULL) {
- id_restore = sound_new_file(bmain, ((bSound *)ID_PT)->name);
+ id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name);
(ID_PT)->newid = id_restore; /* reuse next time */
}
break;
@@ -531,6 +562,7 @@ void BKE_sequencer_new_render_data(
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
r_context->is_proxy_render = false;
+ r_context->view_id = 0;
}
/* ************************* iterator ************************** */
@@ -652,7 +684,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metase
if (seq->start + seq->len - seq->endofs > end)
endofs = seq->start + seq->len - end;
- sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs,
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs,
seq->start + seq->len - endofs, startofs + seq->anim_startofs);
}
}
@@ -765,10 +797,17 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
}
+static void seq_multiview_name(Scene *scene, const size_t view_id, const char *prefix,
+ const char *ext, char *r_path, size_t r_size)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
+}
+
/* note: caller should run BKE_sequence_calc(scene, seq) after */
void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_range)
{
- char str[FILE_MAX];
+ char path[FILE_MAX];
int prev_startdisp = 0, prev_enddisp = 0;
/* note: don't rename the strip, will break animation curves */
@@ -801,22 +840,67 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
break;
}
case SEQ_TYPE_MOVIE:
- BLI_join_dirfile(str, sizeof(str), seq->strip->dir,
+ {
+ StripAnim *sanim;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
seq->strip->stripdata->name);
- BLI_path_abs(str, G.main->name);
+ BLI_path_abs(path, G.main->name);
+
+ BKE_sequence_free_anim(seq);
+
+ if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ int i = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ struct anim *anim;
+ char str[FILE_MAX];
- if (seq->anim) IMB_free_anim(seq->anim);
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
- seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
+ if (anim) {
+ seq_anim_add_suffix(scene, anim, i);
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ struct anim *anim;
+ anim = openanim(path, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
- if (!seq->anim) {
+ /* use the first video as reference for everything */
+ sanim = seq->anims.first;
+
+ if ((!sanim) || (!sanim->anim)) {
return;
}
- seq->len = IMB_anim_get_duration(seq->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
-
- seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
+ seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
+
+ seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
seq->len -= seq->anim_startofs;
seq->len -= seq->anim_endofs;
@@ -824,6 +908,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
seq->len = 0;
}
break;
+ }
case SEQ_TYPE_MOVIECLIP:
if (seq->clip == NULL)
return;
@@ -1076,30 +1161,25 @@ static void make_black_ibuf(ImBuf *ibuf)
}
}
-static void multibuf(ImBuf *ibuf, float fmul)
+static void multibuf(ImBuf *ibuf, const float fmul)
{
char *rt;
float *rt_float;
- int a, mul, icol;
+ int a;
- mul = (int)(256.0f * fmul);
rt = (char *)ibuf->rect;
rt_float = ibuf->rect_float;
if (rt) {
+ const int imul = (int)(256.0f * fmul);
a = ibuf->x * ibuf->y;
while (a--) {
+ rt[0] = min_ii((imul * rt[0]) >> 8, 255);
+ rt[1] = min_ii((imul * rt[1]) >> 8, 255);
+ rt[2] = min_ii((imul * rt[2]) >> 8, 255);
+ rt[3] = min_ii((imul * rt[3]) >> 8, 255);
- icol = (mul * rt[0]) >> 8;
- if (icol > 254) rt[0] = 255; else rt[0] = icol;
- icol = (mul * rt[1]) >> 8;
- if (icol > 254) rt[1] = 255; else rt[1] = icol;
- icol = (mul * rt[2]) >> 8;
- if (icol > 254) rt[2] = 255; else rt[2] = icol;
- icol = (mul * rt[3]) >> 8;
- if (icol > 254) rt[3] = 255; else rt[3] = icol;
-
rt += 4;
}
}
@@ -1181,7 +1261,7 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfr
seq = seqbase->first;
while (seq) {
if (seq->startdisp <= cfra && seq->enddisp > cfra) {
- if ((seq->type & SEQ_TYPE_EFFECT)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
if (seq->seq1) {
effect_inputs[num_effect_inputs++] = seq->seq1;
}
@@ -1291,6 +1371,7 @@ typedef struct SeqIndexBuildContext {
int size_flags;
int quality;
bool overwrite;
+ size_t view_id;
Main *bmain;
Scene *scene;
@@ -1330,54 +1411,164 @@ static double seq_rendersize_to_scale_factor(int size)
return 0.25;
}
-static void seq_open_anim_file(Sequence *seq, bool openfile)
+/* the number of files will vary according to the stereo format */
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+{
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BKE_scene_multiview_num_views_get(&scene->r);
+ }
+}
+
+static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
{
+ char dir[FILE_MAX];
+ char fname[FILE_MAXFILE];
+
+ IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
+ BLI_strncpy(dir, base_dir, sizeof(dir));
+ BLI_path_append(dir, sizeof(dir), fname);
+ IMB_anim_set_index_dir(anim, dir);
+}
+
+static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
+{
+ char dir[FILE_MAX];
char name[FILE_MAX];
StripProxy *proxy;
+ bool use_proxy;
+ bool is_multiview_loaded = false;
+ Editing *ed = scene->ed;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
- if (seq->anim != NULL) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
return;
}
+ /* reset all the previously created anims */
+ BKE_sequence_free_anim(seq);
+
BLI_join_dirfile(name, sizeof(name),
seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
-
- if (openfile) {
- seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- seq->anim = openanim_noload(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- if (seq->anim == NULL) {
- return;
+ proxy = seq->strip->proxy;
+
+ use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
+ (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
+
+ if (use_proxy) {
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+ }
+ else {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ BLI_path_abs(dir, G.main->name);
}
- proxy = seq->strip->proxy;
+ if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ int i;
- if (proxy == NULL) {
- return;
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+ char str[FILE_MAX];
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+
+ BLI_addtail(&seq->anims, sanim);
+
+ BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
+
+ if (openfile) {
+ sanim->anim = openanim(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim) {
+#if 0
+ seq_anim_add_suffix(scene, sanim->anim, i);
+#else
+ /* we already have the suffix */
+ IMB_suffix_anim(sanim->anim, suffix);
+#endif
+ }
+ else {
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ /* no individual view files - monoscopic, stereo 3d or exr multiview */
+ totfiles = 1;
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+ is_multiview_loaded = true;
+ }
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
- char dir[FILE_MAX];
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- BLI_path_abs(dir, G.main->name);
+ if (is_multiview_loaded == false) {
+ StripAnim *sanim;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
- IMB_anim_set_index_dir(seq->anim, dir);
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
}
}
-
-static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *name)
+static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const size_t view_id)
{
int frameno;
char dir[PROXY_MAXFILE];
+ StripAnim *sanim;
+ char suffix[24] = {'\0'};
- if (!seq->strip->proxy) {
+ StripProxy *proxy = seq->strip->proxy;
+ if (!proxy) {
return false;
}
@@ -1389,8 +1580,32 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
* have both, a directory full of jpeg files and proxy avis, so
* sorry folks, please rebuild your proxies... */
- if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR | SEQ_USE_PROXY_CUSTOM_FILE)) {
+ sanim = BLI_findlink(&seq->anims, view_id);
+
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ char fname[FILE_MAXFILE];
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+
+ if (sanim && sanim->anim) {
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ }
+ else if (seq->type == SEQ_TYPE_IMAGE) {
+ fname[0] = 0;
+ }
+ BLI_path_append(dir, sizeof(dir), fname);
+ BLI_path_abs(name, G.main->name);
+ }
+ else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
+ char fname[FILE_MAXFILE];
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ BLI_path_append(dir, sizeof(dir), fname);
}
else if (seq->type == SEQ_TYPE_IMAGE) {
BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
@@ -1399,10 +1614,16 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
return false;
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (view_id > 0)
+ BLI_snprintf(suffix, sizeof(suffix), "_%zu", view_id);
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
+ ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
+ {
BLI_join_dirfile(name, PROXY_MAXFILE,
- dir, seq->strip->proxy->file);
+ dir, proxy->file);
BLI_path_abs(name, G.main->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix);
return true;
}
@@ -1410,13 +1631,13 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
/* generate a separate proxy directory for each preview size */
if (seq->type == SEQ_TYPE_IMAGE) {
- BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, render_size,
- BKE_sequencer_give_stripelem(seq, cfra)->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, render_size,
+ BKE_sequencer_give_stripelem(seq, cfra)->name, suffix);
frameno = 1;
}
else {
frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, render_size);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
}
BLI_path_abs(name, G.main->name);
@@ -1433,45 +1654,48 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
int size_flags;
int render_size = context->preview_render_size;
+ StripProxy *proxy = seq->strip->proxy;
+ Editing *ed = context->scene->ed;
+ StripAnim *sanim;
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return NULL;
+ }
/* dirty hack to distinguish 100% render size from PROXY_100 */
if (render_size == 99) {
render_size = 100;
}
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
- }
-
- size_flags = seq->strip->proxy->build_size_flags;
+ size_flags = proxy->build_size_flags;
/* only use proxies, if they are enabled (even if present!) */
if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
return NULL;
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- if (seq->strip->proxy->anim == NULL) {
- if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) {
+ if (proxy->anim == NULL) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
- seq->strip->proxy->anim = openanim(name, IB_rect, 0,
- seq->strip->colorspace_settings.name);
+ proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
}
- if (seq->strip->proxy->anim == NULL) {
+ if (proxy->anim == NULL) {
return NULL;
}
- seq_open_anim_file(seq, true);
+ seq_open_anim_file(context->scene, seq, true);
+ sanim = seq->anims.first;
- frameno = IMB_anim_index_get_frame_index(seq->anim, seq->strip->proxy->tc, frameno);
+ frameno = IMB_anim_index_get_frame_index(sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
- return IMB_anim_absolute(seq->strip->proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
+ return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
- if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -1496,8 +1720,9 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
int rectx, recty;
int ok;
ImBuf *ibuf_tmp, *ibuf;
+ Editing *ed = context->scene->ed;
- if (!seq_proxy_get_fname(seq, cfra, proxy_render_size, name)) {
+ if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
return;
}
@@ -1512,6 +1737,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
ibuf = IMB_dupImBuf(ibuf_tmp);
+ IMB_metadata_copy(ibuf, ibuf_tmp);
IMB_freeImBuf(ibuf_tmp);
IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
}
@@ -1538,44 +1764,133 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
IMB_freeImBuf(ibuf);
}
-SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list)
+/* returns whether the file this context would read from even exist, if not, don't create the context
+*/
+static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const size_t view_id)
+{
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ static char prefix[FILE_MAX];
+ static const char *ext = NULL;
+ char str[FILE_MAX];
+
+ if (view_id == 0) {
+ char path[FILE_MAX];
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
+ seq->strip->stripdata->name);
+ BLI_path_abs(path, G.main->name);
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ if (prefix[0] == '\0')
+ return view_id != 0;
+
+ seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
+
+ if (BLI_access(str, R_OK) == 0)
+ return false;
+ else
+ return view_id != 0;
+ }
+ return false;
+}
+
+/** This returns the maximum possible number of required contexts
+*/
+static size_t seq_proxy_context_count(Sequence *seq, Scene *scene)
+{
+ size_t num_views = 1;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE:
+ {
+ num_views = BLI_listbase_count(&seq->anims);
+ break;
+ }
+ case SEQ_TYPE_IMAGE:
+ {
+ switch (seq->views_format) {
+ case R_IMF_VIEWS_INDIVIDUAL:
+ num_views = BKE_scene_multiview_num_views_get(&scene->r);
+ break;
+ case R_IMF_VIEWS_STEREO_3D:
+ num_views = 2;
+ break;
+ case R_IMF_VIEWS_MULTIVIEW:
+ /* not supported at the moment */
+ /* pass through */
+ default:
+ num_views = 1;
+ }
+ break;
+ }
+ }
+
+ return num_views;
+}
+
+void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
+ LinkData *link;
+ size_t i;
+ size_t num_files;
if (!seq->strip || !seq->strip->proxy) {
- return NULL;
+ return;
}
if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
+ return;
}
- context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+ num_files = seq_proxy_context_count(seq, scene);
+
+ for (i = 0; i < num_files; i++) {
+ if (seq_proxy_multiview_context_invalid(seq, scene, i))
+ continue;
+
+ context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+
+ nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
+
+ context->tc_flags = nseq->strip->proxy->build_tc_flags;
+ context->size_flags = nseq->strip->proxy->build_size_flags;
+ context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
- nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
+ context->bmain = bmain;
+ context->scene = scene;
+ context->orig_seq = seq;
+ context->seq = nseq;
- context->tc_flags = nseq->strip->proxy->build_tc_flags;
- context->size_flags = nseq->strip->proxy->build_size_flags;
- context->quality = nseq->strip->proxy->quality;
- context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
+ context->view_id = i; /* only for images */
- context->bmain = bmain;
- context->scene = scene;
- context->orig_seq = seq;
- context->seq = nseq;
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
- if (nseq->type == SEQ_TYPE_MOVIE) {
- seq_open_anim_file(nseq, true);
+ if (nseq->type == SEQ_TYPE_MOVIE) {
+ StripAnim *sanim;
- if (nseq->anim) {
- context->index_context = IMB_anim_index_rebuild_context(nseq->anim,
- context->tc_flags, context->size_flags, context->quality,
- context->overwrite, file_list);
+ seq_open_anim_file(scene, nseq, true);
+ sanim = BLI_findlink(&nseq->anims, i);
+
+ if (sanim->anim) {
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags, context->size_flags, context->quality,
+ context->overwrite, file_list);
+ }
}
}
-
- return context;
}
void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
@@ -1600,7 +1915,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
}
/* that's why it is called custom... */
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
return;
}
@@ -1614,6 +1929,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
render_context.skip_cache = true;
render_context.is_proxy_render = true;
+ render_context.view_id = context->view_id;
for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
if (context->size_flags & IMB_PROXY_25) {
@@ -1640,8 +1956,14 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
- IMB_close_anim_proxies(context->seq->anim);
- IMB_close_anim_proxies(context->orig_seq->anim);
+ StripAnim *sanim;
+
+ for (sanim = context->seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
+ for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
@@ -1920,7 +2242,10 @@ static void *color_balance_do_thread(void *thread_data_v)
return NULL;
}
-ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int cfra, bool make_float)
+/* cfra is offset by fra_offset only in case we are using a real mask. */
+ImBuf *BKE_sequencer_render_mask_input(
+ const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id,
+ int cfra, int fra_offset, bool make_float)
{
ImBuf *mask_input = NULL;
@@ -1939,7 +2264,7 @@ ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_in
}
}
else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
- mask_input = seq_render_mask(context, mask_id, cfra, make_float);
+ mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
}
return mask_input;
@@ -2099,6 +2424,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
sequencer_imbuf_assign_spaces(scene, i);
+ IMB_metadata_copy(i, ibuf);
IMB_freeImBuf(ibuf);
ibuf = i;
@@ -2150,6 +2476,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
if (ibuf_new != ibuf) {
+ IMB_metadata_copy(ibuf_new, ibuf);
IMB_freeImBuf(ibuf);
ibuf = ibuf_new;
}
@@ -2172,6 +2499,7 @@ static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq,
if (ibuf) {
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
IMB_freeImBuf(ibuf);
}
@@ -2185,9 +2513,11 @@ static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, floa
/* we have to store a copy, since the passed ibuf
* could be preprocessed afterwards (thereby silently
* changing the cached image... */
- ibuf = IMB_dupImBuf(ibuf);
+ ImBuf *oibuf = ibuf;
+ ibuf = IMB_dupImBuf(oibuf);
if (ibuf) {
+ IMB_metadata_copy(ibuf, oibuf);
sequencer_imbuf_assign_spaces(context->scene, ibuf);
}
@@ -2383,6 +2713,237 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
return out;
}
+static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ char name[FILE_MAX];
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ int flag;
+
+ if (s_elem) {
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, G.main->name);
+ }
+
+ flag = IB_rect | IB_metadata;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
+ flag |= IB_alphamode_premul;
+
+ if (!s_elem) {
+ /* don't do anything */
+ }
+ else if (is_multiview) {
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ size_t totviews;
+ struct ImBuf **ibufs_arr;
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ int i;
+
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ if (prefix[0] == '\0') {
+ goto monoview_image;
+ }
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+
+ if (prefix[0] == '\0') {
+ ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
+ ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibufs_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect)
+ imb_freerectImBuf(ibufs_arr[i]);
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0])
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i]) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+ if (ibuf) {
+ s_elem->orig_width = ibufs_arr[0]->x;
+ s_elem->orig_height = ibufs_arr[0]->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibufs_arr);
+ }
+ else {
+monoview_image:
+ if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect)
+ imb_freerectImBuf(ibuf);
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim;
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+
+ /* load all the videos */
+ seq_open_anim_file(context->scene, seq, false);
+
+ if (is_multiview) {
+ ImBuf **ibuf_arr;
+ size_t totviews;
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int i;
+
+ if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1))
+ goto monoview_movie;
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ if (sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect)
+ imb_freerectImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (ibuf_arr[0]) {
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+ else {
+ /* probably proxy hasn't been created yet */
+ MEM_freeN(ibuf_arr);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ if (ibuf_arr[i]) {
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ }
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[context->view_id];
+ if (ibuf) {
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibuf_arr);
+ }
+ else {
+monoview_movie:
+ sanim = seq->anims.first;
+ if (sanim && sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf) {
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+ }
+ }
+ return ibuf;
+}
+
static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr)
{
ImBuf *ibuf = NULL;
@@ -2514,7 +3075,7 @@ static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq,
return seq_render_mask(context, seq->mask, nr, make_float);
}
-static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr)
+static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
{
ImBuf *ibuf = NULL;
float frame;
@@ -2612,6 +3173,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
char err_out[256] = "unknown";
int width = (scene->r.xsch * scene->r.size) / 100;
int height = (scene->r.ysch * scene->r.size) / 100;
+ const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
/* for old scened this can be uninitialized,
* should probably be added to do_versions at some point if the functionality stays */
@@ -2623,14 +3185,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect,
context->scene->r.seq_prev_type,
(context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
- use_gpencil, true, scene->r.alphamode, err_out);
+ use_gpencil, true, scene->r.alphamode, viewname, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
}
else {
Render *re = RE_GetRender(scene->id.name);
- RenderResult rres;
+ size_t totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ int i;
+ ImBuf **ibufs_arr;
+
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
/* XXX: this if can be removed when sequence preview rendering uses the job system
*
@@ -2650,27 +3216,51 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
}
-
- RE_AcquireResultImage(re, &rres);
-
- if (rres.rectf) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibuf->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
- if (rres.rectz) {
- addzbuffloatImBuf(ibuf);
- memcpy(ibuf->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ RenderResult rres;
+
+ localcontext.view_id = i;
+
+ RE_AcquireResultImage(re, &rres, i);
+
+ if (rres.rectf) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+
+ if (rres.rectz) {
+ addzbuffloatImBuf(ibufs_arr[i]);
+ memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ }
+
+ /* float buffers in the sequencer are not linear */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ }
+ else if (rres.rect32) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
}
- /* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+
+ RE_ReleaseResultImage(re);
}
- else if (rres.rect32) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibuf->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
}
-
- RE_ReleaseResultImage(re);
-
+ MEM_freeN(ibufs_arr);
+
// BIF_end_render_callbacks();
}
@@ -2697,7 +3287,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
float nr = give_stripelem_index(seq, cfra);
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- char name[FILE_MAX];
switch (type) {
case SEQ_TYPE_META:
@@ -2756,64 +3345,14 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_IMAGE:
{
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- int flag;
-
- if (s_elem) {
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, G.main->name);
- }
-
- flag = IB_rect;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
- flag |= IB_alphamode_premul;
-
- if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect)
- imb_freerectImBuf(ibuf);
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
-
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- }
+ ibuf = seq_render_image_strip(context, seq, nr, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
case SEQ_TYPE_MOVIE:
{
- seq_open_anim_file(seq, false);
-
- if (seq->anim) {
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
- IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
-
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf && proxy_size != IMB_PROXY_NONE) {
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- }
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
@@ -2821,7 +3360,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_SCENE:
{
/* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr);
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
@@ -3050,6 +3589,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+ IMB_metadata_copy(out, ibuf2);
+
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
}
@@ -3318,16 +3859,6 @@ ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, float cfra
return e ? e->ibuf : NULL;
}
-/* Functions to free imbuf and anim data on changes */
-
-static void free_anim_seq(Sequence *seq)
-{
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-}
-
/* check whether sequence cur depends on seq */
bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
{
@@ -3379,15 +3910,11 @@ static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalida
/* invalidate cache for current sequence */
if (invalidate_self) {
- if (seq->anim) {
- /* Animation structure holds some buffers inside,
- * so for proper cache invalidation we need to
- * re-open the animation.
- */
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-
+ /* Animation structure holds some buffers inside,
+ * so for proper cache invalidation we need to
+ * re-open the animation.
+ */
+ BKE_sequence_free_anim(seq);
BKE_sequencer_cache_cleanup_sequence(seq);
}
@@ -3434,7 +3961,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
if (seq->strip) {
if (seq->type == SEQ_TYPE_MOVIE) {
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
}
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
@@ -3481,7 +4008,7 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha
if (free_imbuf) {
if (ibuf_change) {
if (seq->type == SEQ_TYPE_MOVIE)
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
@@ -3733,10 +4260,10 @@ void BKE_sequence_sound_init(Scene *scene, Sequence *seq)
}
else {
if (seq->sound) {
- seq->scene_sound = sound_add_scene_sound_defaults(scene, seq);
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
}
if (seq->scene) {
- seq->scene_sound = sound_scene_add_scene_sound_defaults(scene, seq);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
}
}
}
@@ -3948,11 +4475,11 @@ void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq)
/* We have to take into account start frame of the sequence's scene! */
int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
- sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
}
}
else {
- sound_move_scene_sound_defaults(scene, seq);
+ BKE_sound_move_scene_sound_defaults(scene, seq);
}
/* mute is set in seq_update_muting_recursive */
}
@@ -3977,7 +4504,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
if (seq->scene_sound) {
- sound_mute_scene_sound(seq->scene_sound, seqmute);
+ BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
}
}
}
@@ -4006,7 +4533,7 @@ static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->scene_sound && sound == seq->sound) {
- sound_update_scene_sound(seq->scene_sound, sound);
+ BKE_sound_update_scene_sound(seq->scene_sound, sound);
}
}
}
@@ -4121,7 +4648,7 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char
char name_esc[SEQ_NAME_MAXSTR * 2];
BLI_strescape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+ return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
@@ -4339,7 +4866,7 @@ static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
if (seq->sound)
- sound_cache(seq->sound);
+ BKE_sound_cache(seq->sound);
}
seq_load->tot_success++;
@@ -4369,6 +4896,8 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine)
seq->pitch = 1.0f;
seq->scene_sound = NULL;
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+
return seq;
}
@@ -4426,6 +4955,12 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
+ if (seq_load->stereo3d_format)
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+
+ seq->views_format = seq_load->views_format;
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq_load_apply(scene, seq, seq_load);
return seq;
@@ -4445,9 +4980,9 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
AUD_SoundInfo info;
- sound = sound_new_file(bmain, seq_load->path); /* handles relative paths */
+ sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -4459,7 +4994,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- sound_delete(bmain, sound);
+ BKE_sound_delete(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -4484,7 +5019,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
- seq->scene_sound = sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
@@ -4505,6 +5040,12 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
#endif // WITH_AUDASPACE
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ IMB_suffix_anim(anim, suffix);
+}
+
Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
Scene *scene = CTX_data_scene(C); /* only for sound */
@@ -4514,29 +5055,84 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
StripElem *se;
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
-
- struct anim *an;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
+ size_t totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ struct anim **anim_arr;
+ int i;
BLI_strncpy(path, seq_load->path, sizeof(path));
BLI_path_abs(path, G.main->name);
- an = openanim(path, IB_rect, 0, colorspace);
+ anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
- if (an == NULL)
- return NULL;
+ if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ size_t j = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
+
+ if (anim_arr[j]) {
+ seq_anim_add_suffix(scene, anim_arr[j], i);
+ j++;
+ }
+ }
+
+ if (j == 0) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
+
+ if (anim_arr[0] == NULL) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ }
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+
+ /* multiview settings */
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ seq->views_format = seq_load->views_format;
+ }
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq->type = SEQ_TYPE_MOVIE;
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- seq->anim = an;
- seq->anim_preseek = IMB_anim_get_preseek(an);
+ for (i = 0; i < totfiles; i++) {
+ if (anim_arr[i]) {
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim_arr[i];
+ }
+ else {
+ break;
+ }
+ }
+
+ seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
+ seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
strip->us = 1;
BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name));
@@ -4564,6 +5160,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
/* can be NULL */
seq_load_apply(scene, seq, seq_load);
+ MEM_freeN(anim_arr);
return seq;
}
@@ -4575,6 +5172,8 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seq->tmp = seqn;
seqn->strip = MEM_dupallocN(seq->strip);
+ seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
+
/* XXX: add F-Curve duplication stuff? */
if (seq->strip->crop) {
@@ -4590,6 +5189,10 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seqn->strip->proxy->anim = NULL;
}
+ if (seq->prop) {
+ seqn->prop = IDP_CopyProperty(seq->prop);
+ }
+
if (seqn->modifiers.first) {
BLI_listbase_clear(&seqn->modifiers);
@@ -4606,7 +5209,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 = sound_scene_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn);
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
/* avoid assert */
@@ -4617,13 +5220,13 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
else if (seq->type == SEQ_TYPE_MOVIE) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
- seqn->anim = NULL;
+ BLI_listbase_clear(&seqn->anims);
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
if (seq->scene_sound)
- seqn->scene_sound = sound_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn);
id_us_plus((ID *)seqn->sound);
}
@@ -4632,10 +5235,6 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
MEM_dupallocN(seq->strip->stripdata);
}
else if (seq->type >= SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->tmp) seqn->seq1 = seq->seq1->tmp;
- if (seq->seq2 && seq->seq2->tmp) seqn->seq2 = seq->seq2->tmp;
- if (seq->seq3 && seq->seq3->tmp) seqn->seq3 = seq->seq3->tmp;
-
if (seq->type & SEQ_TYPE_EFFECT) {
struct SeqEffectHandle sh;
sh = BKE_sequence_get_effect(seq);
@@ -4660,6 +5259,28 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
return seqn;
}
+static void seq_new_fix_links_recursive(Sequence *seq)
+{
+ SequenceModifierData *smd;
+
+ if (seq->type >= SEQ_TYPE_EFFECT) {
+ if (seq->seq1 && seq->seq1->tmp) seq->seq1 = seq->seq1->tmp;
+ if (seq->seq2 && seq->seq2->tmp) seq->seq2 = seq->seq2->tmp;
+ if (seq->seq3 && seq->seq3->tmp) seq->seq3 = seq->seq3->tmp;
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ Sequence *seqn;
+ for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
+ seq_new_fix_links_recursive(seqn);
+ }
+ }
+
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence && smd->mask_sequence->tmp)
+ smd->mask_sequence = smd->mask_sequence->tmp;
+ }
+}
+
Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag)
{
Sequence *seqn = seq_dupli(scene, scene_to, seq, dupe_flag);
@@ -4672,6 +5293,9 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *
}
}
}
+
+ seq_new_fix_links_recursive(seqn);
+
return seqn;
}
@@ -4710,6 +5334,11 @@ void BKE_sequence_base_dupli_recursive(
}
}
}
+
+ /* fix modifier linking */
+ for (seq = nseqbase->first; seq; seq = seq->next) {
+ seq_new_fix_links_recursive(seq);
+ }
}
/* called on draw, needs to be fast,
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 559e1e05f3f..28a2c42546d 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -66,6 +66,7 @@
#include "BKE_bvhutils.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -266,7 +267,7 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
}
/* apply object scale */
for (i = 0; i < 3; i++) {
- size[i] = fabs(size[i] * ob->size[i]);
+ size[i] = fabsf(size[i] * ob->size[i]);
}
copy_v3_v3(sds->global_size, size);
copy_v3_v3(sds->dp0, min);
@@ -971,7 +972,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int
/* also update constraint targets */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
@@ -1239,6 +1240,12 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
sim.ob = flow_ob;
sim.psys = psys;
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+
/* initialize particle cache */
if (psys->part->type == PART_HAIR) {
// TODO: PART_HAIR not supported whatsoever
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 3cc2337d4f1..607f89699a4 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1035,6 +1035,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
#if 0 /* UNUSED */
@@ -1076,6 +1077,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
}
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1114,6 +1116,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MVert *mvert= NULL;
@@ -1177,6 +1180,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
} /* if (mvert) */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1206,6 +1210,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1315,6 +1320,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1434,6 +1440,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1555,6 +1562,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1762,6 +1770,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1799,7 +1808,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
else {
/*aye that should be cached*/
printf("missing cache error\n");
- BLI_ghashIterator_step(ihash);
+ BLI_ghashIterator_step(ihash);
continue;
}
@@ -1917,16 +1926,16 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
if (facedist > outerfacethickness*ff)
force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
*damp=ob->pd->pdef_sbdamp;
- if (facedist > 0.0f) {
- *damp *= (1.0f - facedist/outerfacethickness);
- Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
- deflected = 3;
+ if (facedist > 0.0f) {
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
+ deflected = 3;
- }
- else {
- Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
- if (deflected < 2) deflected = 2;
- }
+ }
+ else {
+ Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
+ if (deflected < 2) deflected = 2;
+ }
if ((mprevvert) && (*damp > 0.0f)) {
choose_winner(ve, opco, nv1, nv3, nv4, vv1, vv3, vv4);
@@ -1997,6 +2006,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
if (deflected == 1) { // no face but 'outer' edge cylinder sees vert
@@ -2335,14 +2345,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
float kd = 1.0f;
if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
- if (intrusion < 0.0f) {
- sb->scratch->flag |= SBF_DOFUZZY;
- bp->loc_flag |= SBF_DOFUZZY;
- bp->choke = sb->choke*0.01f;
- }
+ if (intrusion < 0.0f) {
+ sb->scratch->flag |= SBF_DOFUZZY;
+ bp->loc_flag |= SBF_DOFUZZY;
+ bp->choke = sb->choke*0.01f;
+ }
- sub_v3_v3v3(cfforce, bp->vec, vel);
- Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
+ sub_v3_v3v3(cfforce, bp->vec, vel);
+ Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
Vec3PlusStVec(bp->force, kd, defforce);
}
@@ -3484,7 +3494,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object
bs->v1 = bpc;
bs->v2 = bpc+dw+dv-1;
bs->springtype=SB_BEND;
- bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
+ bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
bs++;
}
}
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index b9d70664874..46a50917427 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -64,9 +64,9 @@
static int sound_cfra;
#endif
-bSound *sound_new_file(struct Main *bmain, const char *filename)
+bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
{
- bSound *sound = NULL;
+ bSound *sound;
char str[FILE_MAX];
const char *path;
@@ -87,12 +87,7 @@ bSound *sound_new_file(struct Main *bmain, const char *filename)
BLI_strncpy(sound->name, filename, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
- sound_load(bmain, sound);
-
- if (!sound->playback_handle) {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
+ BKE_sound_load(bmain, sound);
return sound;
}
@@ -116,7 +111,7 @@ void BKE_sound_free(bSound *sound)
sound->cache = NULL;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
@@ -141,18 +136,18 @@ static void sound_sync_callback(void *data, int mode, float time)
while (scene) {
if (scene->audio.flag & AUDIO_SYNC) {
if (mode)
- sound_play_scene(scene);
+ BKE_sound_play_scene(scene);
else
- sound_stop_scene(scene);
- if (scene->sound_scene_handle)
- AUD_seek(scene->sound_scene_handle, time);
+ BKE_sound_stop_scene(scene);
+ if (scene->playback_handle)
+ AUD_seek(scene->playback_handle, time);
}
scene = scene->id.next;
}
}
#endif
-int sound_define_from_str(const char *str)
+int BKE_sound_define_from_str(const char *str)
{
if (BLI_strcaseeq(str, "NULL"))
return AUD_NULL_DEVICE;
@@ -166,18 +161,18 @@ int sound_define_from_str(const char *str)
return -1;
}
-void sound_force_device(int device)
+void BKE_sound_force_device(int device)
{
force_device = device;
}
-void sound_init_once(void)
+void BKE_sound_init_once(void)
{
AUD_initOnce();
- atexit(sound_exit_once);
+ atexit(BKE_sound_exit_once);
}
-void sound_init(struct Main *bmain)
+void BKE_sound_init(struct Main *bmain)
{
AUD_DeviceSpecs specs;
int device, buffersize;
@@ -206,10 +201,10 @@ void sound_init(struct Main *bmain)
if (!AUD_init(device, specs, buffersize))
AUD_init(AUD_NULL_DEVICE, specs, buffersize);
- sound_init_main(bmain);
+ BKE_sound_init_main(bmain);
}
-void sound_init_main(struct Main *bmain)
+void BKE_sound_init_main(struct Main *bmain)
{
#ifdef WITH_JACK
AUD_setSyncCallback(sound_sync_callback, bmain);
@@ -218,12 +213,12 @@ void sound_init_main(struct Main *bmain)
#endif
}
-void sound_exit(void)
+void BKE_sound_exit(void)
{
AUD_exit();
}
-void sound_exit_once(void)
+void BKE_sound_exit_once(void)
{
AUD_exit();
AUD_exitOnce();
@@ -231,7 +226,7 @@ void sound_exit_once(void)
/* XXX unused currently */
#if 0
-bSound *sound_new_buffer(struct Main *bmain, bSound *source)
+bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source)
{
bSound *sound = NULL;
@@ -246,16 +241,10 @@ bSound *sound_new_buffer(struct Main *bmain, bSound *source)
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
-bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float end)
+bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, float end)
{
bSound *sound = NULL;
@@ -272,17 +261,11 @@ bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
#endif
-void sound_delete(struct Main *bmain, bSound *sound)
+void BKE_sound_delete(struct Main *bmain, bSound *sound)
{
if (sound) {
BKE_sound_free(sound);
@@ -291,7 +274,7 @@ void sound_delete(struct Main *bmain, bSound *sound)
}
}
-void sound_cache(bSound *sound)
+void BKE_sound_cache(bSound *sound)
{
sound->flags |= SOUND_FLAGS_CACHING;
if (sound->cache)
@@ -304,7 +287,7 @@ void sound_cache(bSound *sound)
sound->playback_handle = sound->handle;
}
-void sound_delete_cache(bSound *sound)
+void BKE_sound_delete_cache(bSound *sound)
{
sound->flags &= ~SOUND_FLAGS_CACHING;
if (sound->cache) {
@@ -314,7 +297,7 @@ void sound_delete_cache(bSound *sound)
}
}
-void sound_load(struct Main *bmain, bSound *sound)
+void BKE_sound_load(struct Main *bmain, bSound *sound)
{
if (sound) {
if (sound->cache) {
@@ -328,7 +311,7 @@ void sound_load(struct Main *bmain, bSound *sound)
sound->playback_handle = NULL;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
/* XXX unused currently */
#if 0
@@ -382,16 +365,16 @@ void sound_load(struct Main *bmain, bSound *sound)
else
sound->playback_handle = sound->handle;
- sound_update_sequencer(bmain, sound);
+ BKE_sound_update_sequencer(bmain, sound);
}
}
-AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
+AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
}
-void sound_create_scene(struct Scene *scene)
+void BKE_sound_create_scene(struct Scene *scene)
{
/* should be done in version patch, but this gets called before */
if (scene->r.frs_sec_base == 0)
@@ -400,15 +383,15 @@ void sound_create_scene(struct Scene *scene)
scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE);
AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound,
scene->audio.doppler_factor, scene->audio.distance_model);
- scene->sound_scene_handle = NULL;
+ scene->playback_handle = NULL;
scene->sound_scrub_handle = NULL;
scene->speaker_handles = NULL;
}
-void sound_destroy_scene(struct Scene *scene)
+void BKE_sound_destroy_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
if (scene->sound_scrub_handle)
AUD_stop(scene->sound_scrub_handle);
if (scene->sound_scene)
@@ -417,13 +400,13 @@ void sound_destroy_scene(struct Scene *scene)
AUD_destroySet(scene->speaker_handles);
}
-void sound_mute_scene(struct Scene *scene, int muted)
+void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
if (scene->sound_scene)
AUD_setSequencerMuted(scene->sound_scene, muted);
}
-void sound_update_fps(struct Scene *scene)
+void BKE_sound_update_fps(struct Scene *scene)
{
if (scene->sound_scene)
AUD_setSequencerFPS(scene->sound_scene, FPS);
@@ -431,13 +414,13 @@ void sound_update_fps(struct Scene *scene)
BKE_sequencer_refresh_sound_length(scene);
}
-void sound_update_scene_listener(struct Scene *scene)
+void BKE_sound_update_scene_listener(struct Scene *scene)
{
AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound,
scene->audio.doppler_factor, scene->audio.distance_model);
}
-void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence,
+void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence,
int startframe, int endframe, int frameskip)
{
if (scene != sequence->scene) {
@@ -448,14 +431,14 @@ void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence
return NULL;
}
-void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return sound_scene_add_scene_sound(scene, sequence,
+ return BKE_sound_scene_add_scene_sound(scene, sequence,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
-void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
+void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
{
const double fps = FPS;
void *handle = AUD_addSequence(scene->sound_scene, sequence->sound->playback_handle,
@@ -467,70 +450,70 @@ void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int
return handle;
}
-void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return sound_add_scene_sound(scene, sequence,
+ return BKE_sound_add_scene_sound(scene, sequence,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
-void sound_remove_scene_sound(struct Scene *scene, void *handle)
+void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle)
{
AUD_removeSequence(scene->sound_scene, handle);
}
-void sound_mute_scene_sound(void *handle, char mute)
+void BKE_sound_mute_scene_sound(void *handle, char mute)
{
AUD_muteSequence(handle, mute);
}
-void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
+void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
{
const double fps = FPS;
AUD_moveSequence(handle, startframe / fps, endframe / fps, frameskip / fps);
}
-void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
if (sequence->scene_sound) {
- sound_move_scene_sound(scene, sequence->scene_sound,
+ BKE_sound_move_scene_sound(scene, sequence->scene_sound,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
}
-void sound_update_scene_sound(void *handle, bSound *sound)
+void BKE_sound_update_scene_sound(void *handle, bSound *sound)
{
AUD_updateSequenceSound(handle, sound->playback_handle);
}
-void sound_set_cfra(int cfra)
+void BKE_sound_set_cfra(int cfra)
{
sound_cfra = cfra;
}
-void sound_set_scene_volume(struct Scene *scene, float volume)
+void BKE_sound_set_scene_volume(struct Scene *scene, float volume)
{
AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume,
(scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
}
-void sound_set_scene_sound_volume(void *handle, float volume, char animated)
+void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated);
}
-void sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
+void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
}
-void sound_set_scene_sound_pan(void *handle, float pan, char animated)
+void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
}
-void sound_update_sequencer(struct Main *main, bSound *sound)
+void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
{
struct Scene *scene;
@@ -541,36 +524,36 @@ void sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
AUD_setSequencerDeviceSpecs(scene->sound_scene);
- if ((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1)))
- AUD_setLoop(scene->sound_scene_handle, -1);
+ if ((scene->playback_handle = AUD_play(scene->sound_scene, 1)))
+ AUD_setLoop(scene->playback_handle, -1);
}
-void sound_play_scene(struct Scene *scene)
+void BKE_sound_play_scene(struct Scene *scene)
{
AUD_Status status;
const float cur_time = (float)((double)CFRA / FPS);
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
}
if (status != AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_resume(scene->sound_scene_handle);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_resume(scene->playback_handle);
}
if (scene->audio.flag & AUDIO_SYNC)
@@ -579,17 +562,17 @@ void sound_play_scene(struct Scene *scene)
AUD_unlock();
}
-void sound_stop_scene(struct Scene *scene)
+void BKE_sound_stop_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
- AUD_pause(scene->sound_scene_handle);
+ if (scene->playback_handle) {
+ AUD_pause(scene->playback_handle);
if (scene->audio.flag & AUDIO_SYNC)
AUD_stopPlayback();
}
}
-void sound_seek_scene(struct Main *bmain, struct Scene *scene)
+void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
{
AUD_Status status;
bScreen *screen;
@@ -600,17 +583,17 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
- AUD_pause(scene->sound_scene_handle);
+ AUD_pause(scene->playback_handle);
}
animation_playing = 0;
@@ -623,13 +606,13 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
- AUD_resume(scene->sound_scene_handle);
+ AUD_resume(scene->playback_handle);
if (scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) {
AUD_seek(scene->sound_scrub_handle, 0);
}
@@ -637,16 +620,16 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
if (scene->sound_scrub_handle) {
AUD_stop(scene->sound_scrub_handle);
}
- scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, one_frame);
+ scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
}
}
else {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
if (status == AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
}
}
@@ -654,18 +637,18 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
AUD_unlock();
}
-float sound_sync_scene(struct Scene *scene)
+float BKE_sound_sync_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
+ if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
- return AUD_getSequencerPosition(scene->sound_scene_handle);
+ return AUD_getSequencerPosition(scene->playback_handle);
else
- return AUD_getPosition(scene->sound_scene_handle);
+ return AUD_getPosition(scene->playback_handle);
}
return NAN_FLT;
}
-int sound_scene_playing(struct Scene *scene)
+int BKE_sound_scene_playing(struct Scene *scene)
{
if (scene->audio.flag & AUDIO_SYNC)
return AUD_doesPlayback();
@@ -673,7 +656,7 @@ int sound_scene_playing(struct Scene *scene)
return -1;
}
-void sound_free_waveform(bSound *sound)
+void BKE_sound_free_waveform(bSound *sound)
{
SoundWaveform *waveform = sound->waveform;
if (waveform) {
@@ -686,7 +669,7 @@ void sound_free_waveform(bSound *sound)
sound->waveform = NULL;
}
-void sound_read_waveform(bSound *sound, short *stop)
+void BKE_sound_read_waveform(bSound *sound, short *stop)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
@@ -717,7 +700,7 @@ void sound_read_waveform(bSound *sound, short *stop)
return;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
BLI_spin_lock(sound->spinlock);
sound->waveform = waveform;
@@ -725,7 +708,7 @@ void sound_read_waveform(bSound *sound, short *stop)
BLI_spin_unlock(sound->spinlock);
}
-void sound_update_scene(Main *bmain, struct Scene *scene)
+void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
{
Object *ob;
Base *base;
@@ -806,20 +789,20 @@ void sound_update_scene(Main *bmain, struct Scene *scene)
scene->speaker_handles = new_set;
}
-void *sound_get_factory(void *sound)
+void *BKE_sound_get_factory(void *sound)
{
return ((bSound *)sound)->playback_handle;
}
/* stupid wrapper because AUD_C-API.h includes Python.h which makesrna doesn't like */
-float sound_get_length(bSound *sound)
+float BKE_sound_get_length(bSound *sound)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
return info.length;
}
-bool sound_is_jack_supported(void)
+bool BKE_sound_is_jack_supported(void)
{
return (bool)AUD_isJackSupported();
}
@@ -828,47 +811,47 @@ bool sound_is_jack_supported(void)
#include "BLI_utildefines.h"
-int sound_define_from_str(const char *UNUSED(str)) { return -1; }
-void sound_force_device(int UNUSED(device)) {}
-void sound_init_once(void) {}
-void sound_init(struct Main *UNUSED(bmain)) {}
-void sound_exit(void) {}
-void sound_exit_once(void) {}
-void sound_cache(struct bSound *UNUSED(sound)) {}
-void sound_delete_cache(struct bSound *UNUSED(sound)) {}
-void sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
-void sound_create_scene(struct Scene *UNUSED(scene)) {}
-void sound_destroy_scene(struct Scene *UNUSED(scene)) {}
-void sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
-void *sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
- int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
-void *sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene),
- struct Sequence *UNUSED(sequence)) { return NULL; }
-void *sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
-void *sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; }
-void sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {}
-void sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {}
-void sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) {}
-void sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {}
-void sound_play_scene(struct Scene *UNUSED(scene)) {}
-void sound_stop_scene(struct Scene *UNUSED(scene)) {}
-void sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-float sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; }
-int sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; }
-void sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); }
-void sound_init_main(struct Main *UNUSED(bmain)) {}
-void sound_set_cfra(int UNUSED(cfra)) {}
-void sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {}
-void sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-void sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {}
-void sound_update_scene_listener(struct Scene *UNUSED(scene)) {}
-void sound_update_fps(struct Scene *UNUSED(scene)) {}
-void sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {}
-void sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {}
-void sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
-void sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
-float sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool sound_is_jack_supported(void) { return false; }
+int BKE_sound_define_from_str(const char *UNUSED(str)) { return -1; }
+void BKE_sound_force_device(int UNUSED(device)) {}
+void BKE_sound_init_once(void) {}
+void BKE_sound_init(struct Main *UNUSED(bmain)) {}
+void BKE_sound_exit(void) {}
+void BKE_sound_exit_once(void) {}
+void BKE_sound_cache(struct bSound *UNUSED(sound)) {}
+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_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; }
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence)) { return NULL; }
+void *BKE_sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe),
+ int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
+void *BKE_sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; }
+void BKE_sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {}
+void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {}
+void BKE_sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe),
+ int UNUSED(endframe), int UNUSED(frameskip)) {}
+void BKE_sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {}
+void BKE_sound_play_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_stop_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
+float BKE_sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; }
+int BKE_sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; }
+void BKE_sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); }
+void BKE_sound_init_main(struct Main *UNUSED(bmain)) {}
+void BKE_sound_set_cfra(int UNUSED(cfra)) {}
+void BKE_sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {}
+void BKE_sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
+void BKE_sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {}
+void BKE_sound_update_scene_listener(struct Scene *UNUSED(scene)) {}
+void BKE_sound_update_fps(struct Scene *UNUSED(scene)) {}
+void BKE_sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {}
+void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {}
+void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
+void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
+float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
+bool BKE_sound_is_jack_supported(void) { return false; }
#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index b11d0ae03b0..7a800555144 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -130,5 +130,5 @@ void BKE_speaker_free(Speaker *spk)
if (spk->sound)
spk->sound->id.us--;
- BKE_free_animdata((ID *)spk);
+ BKE_animdata_free((ID *)spk);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 9519c7b25a1..edf0bfce8c8 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -300,7 +300,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
- vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, 0, limit);
+ /* previous behavior here is without accounting for winding, however this causes stretching in
+ * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially
+ * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED
+ * This fixes a very old regression (2.49 was correct here) */
+ vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true);
if (!vmap)
return 0;
@@ -1762,7 +1766,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
ccgdm_pbvh_update(ccgdm);
if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false);
glShadeModel(GL_FLAT);
@@ -2221,7 +2225,8 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
- MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
+ int colType = CD_TEXTURE_MCOL;
+ MCol *mcol = dm->getTessFaceDataArray(dm, colType);
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
MTFace *tf_stencil_base = NULL;
MTFace *tf_stencil = NULL;
@@ -2239,11 +2244,14 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- if (!mcol)
- mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
-
- if (!mcol)
- mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
+ if (!mcol) {
+ colType = CD_PREVIEW_MCOL;
+ mcol = dm->getTessFaceDataArray(dm, colType);
+ }
+ if (!mcol) {
+ colType = CD_MCOL;
+ mcol = dm->getTessFaceDataArray(dm, colType);
+ }
totface = ccgSubSurf_getNumFaces(ss);
@@ -2796,7 +2804,6 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
- if (ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
if (ccgdm->gridHidden) {
@@ -3107,46 +3114,11 @@ static int ccgDM_getGridSize(DerivedMesh *dm)
return ccgSubSurf_getGridSize(ccgdm->ss);
}
-static int ccgdm_adjacent_grid(int *gridOffset, CCGFace *f, int S, int offset)
-{
- CCGFace *adjf;
- CCGEdge *e;
- int i, j = 0, numFaces, fIndex, numEdges = 0;
-
- e = ccgSubSurf_getFaceEdge(f, S);
- numFaces = ccgSubSurf_getEdgeNumFaces(e);
-
- if (numFaces != 2)
- return -1;
-
- for (i = 0; i < numFaces; i++) {
- adjf = ccgSubSurf_getEdgeFace(e, i);
-
- if (adjf != f) {
- numEdges = ccgSubSurf_getFaceNumVerts(adjf);
- for (j = 0; j < numEdges; j++)
- if (ccgSubSurf_getFaceEdge(adjf, j) == e)
- break;
-
- if (j != numEdges)
- break;
- }
- }
-
- if (numEdges == 0)
- return -1;
-
- fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(adjf));
-
- return gridOffset[fIndex] + (j + offset) % numEdges;
-}
-
static void ccgdm_create_grids(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
CCGElem **gridData;
- DMGridAdjacency *gridAdjacency, *adj;
DMFlagMat *gridFlagMats;
CCGFace **gridFaces;
int *gridOffset;
@@ -3172,7 +3144,6 @@ static void ccgdm_create_grids(DerivedMesh *dm)
/* compute grid data */
gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData");
- gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency) * numGrids, "ccgdm.gridAdjacency");
gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces");
gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats");
@@ -3183,29 +3154,14 @@ static void ccgdm_create_grids(DerivedMesh *dm)
int numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++, gIndex++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1 + numVerts) % numVerts;
-
gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S);
gridFaces[gIndex] = f;
gridFlagMats[gIndex] = ccgdm->faceFlags[index];
-
- adj = &gridAdjacency[gIndex];
-
- adj->index[0] = gIndex - S + nextS;
- adj->rotation[0] = 3;
- adj->index[1] = ccgdm_adjacent_grid(gridOffset, f, prevS, 0);
- adj->rotation[1] = 1;
- adj->index[2] = ccgdm_adjacent_grid(gridOffset, f, S, 1);
- adj->rotation[2] = 3;
- adj->index[3] = gIndex - S + prevS;
- adj->rotation[3] = 1;
}
}
ccgdm->gridData = gridData;
ccgdm->gridFaces = gridFaces;
- ccgdm->gridAdjacency = gridAdjacency;
ccgdm->gridOffset = gridOffset;
ccgdm->gridFlagMats = gridFlagMats;
}
@@ -3218,14 +3174,6 @@ static CCGElem **ccgDM_getGridData(DerivedMesh *dm)
return ccgdm->gridData;
}
-static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-
- ccgdm_create_grids(dm);
- return ccgdm->gridAdjacency;
-}
-
static int *ccgDM_getGridOffset(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -3308,7 +3256,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
* when the ccgdm gets remade, the assumption is that the topology
* does not change. */
ccgdm_create_grids(dm);
- BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces,
+ BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
ccgdm->gridFlagMats, ccgdm->gridHidden);
}
@@ -3327,7 +3275,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids = ccgDM_getNumGrids(dm);
ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
+ BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData,
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
@@ -3455,7 +3403,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
ccgdm->dm.getGridSize = ccgDM_getGridSize;
ccgdm->dm.getGridData = ccgDM_getGridData;
- ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency;
ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
ccgdm->dm.getGridKey = ccgDM_getGridKey;
ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats;
@@ -3820,7 +3767,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
SubsurfFlags flags)
{
int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
- CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0;
+ CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
@@ -3828,7 +3775,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
@@ -3840,7 +3787,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
CCGSubSurf *ss;
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels) : smd->renderLevels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -3856,7 +3803,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
else {
int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
CCGSubSurf *ss;
/* It is quite possible there is a much better place to do this. It
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 9f441b45db9..89456763b95 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -330,7 +330,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
text->curc = text->selc = 0;
}
-int BKE_text_reload(Text *text)
+bool BKE_text_reload(Text *text)
{
FILE *fp;
int len;
@@ -339,13 +339,24 @@ int BKE_text_reload(Text *text)
char str[FILE_MAX];
BLI_stat_t st;
- if (!text->name) return 0;
-
+ if (!text->name) {
+ return false;
+ }
+
BLI_strncpy(str, text->name, FILE_MAX);
BLI_path_abs(str, G.main->name);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return 0;
+ if (fp == NULL) {
+ return false;
+ }
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return false;
+ }
/* free memory: */
@@ -363,11 +374,6 @@ int BKE_text_reload(Text *text)
MEM_freeN(text->undo_buf);
init_undo_text(text);
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
-
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
* of CR stripping */
@@ -385,7 +391,7 @@ int BKE_text_reload(Text *text)
text_from_buf(text, buffer, len);
MEM_freeN(buffer);
- return 1;
+ return true;
}
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
@@ -402,8 +408,18 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
BLI_path_abs(str, relpath);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return NULL;
-
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return NULL;
+ }
+
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str));
ta->id.us = 1;
@@ -423,10 +439,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
/* clear undo buffer */
init_undo_text(ta);
-
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
@@ -473,6 +485,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
BLI_listbase_clear(&tan->lines);
tan->curl = tan->sell = NULL;
+ tan->compiled = NULL;
tan->nlines = ta->nlines;
@@ -651,7 +664,7 @@ void BKE_text_unlink(Main *bmain, Text *text)
}
}
- /* Freestyle (while looping oer the scene) */
+ /* Freestyle (while looping over the scene) */
for (srl = sce->r.layers.first; srl; srl = srl->next) {
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
if (module->script == text)
@@ -1895,6 +1908,47 @@ static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
text->undo_buf[text->undo_pos + 1] = 0;
}
+/* extends Link */
+struct LinkInt {
+ struct LinkInt *next, *prev;
+ int value;
+};
+
+/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers
+ * of the lines that should not be indented back. */
+static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len)
+{
+ struct LinkInt *idata;
+
+ BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
+
+ /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
+ if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
+ return;
+ }
+
+ /* Opening buffer sequence with OP */
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ text->undo_pos++;
+ /* Adding number of line numbers to read */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+
+ /* Adding linenumbers of lines that shall not be indented if undoing */
+ for (idata = line_index_mask->first; idata; idata = idata->next) {
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value);
+ }
+
+ /* Adding number of line numbers to read again */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+ /* Adding current selection */
+ txt_undo_store_cursors(text);
+ /* Closing with OP (same as above) */
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ /* Marking as last undo operation */
+ text->undo_buf[text->undo_pos + 1] = 0;
+}
+
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
{
unsigned short val;
@@ -2189,7 +2243,6 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2203,9 +2256,6 @@ void txt_do_undo(Text *text)
if (op == UNDO_INDENT) {
txt_unindent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_indent(text);
- }
else if (op == UNDO_COMMENT) {
txt_uncomment(text);
}
@@ -2224,6 +2274,37 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+ /* Get and restore the cursors */
+ txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ /* Un-unindent */
+ txt_indent(text);
+
+ /* Get the count */
+ count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Iterate! */
+ txt_pop_sel(text);
+
+ for (i = 0; i < count; i++) {
+ txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0);
+ /* Un-un-unindent */
+ txt_unindent(text);
+ }
+ /* Restore selection */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ /* Jumo over count */
+ txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Jump over closing OP byte */
+ text->undo_pos--;
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2353,7 +2434,6 @@ void txt_do_redo(Text *text)
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2369,9 +2449,6 @@ void txt_do_redo(Text *text)
if (op == UNDO_INDENT) {
txt_indent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_unindent(text);
- }
else if (op == UNDO_COMMENT) {
txt_comment(text);
}
@@ -2401,6 +2478,26 @@ void txt_do_redo(Text *text)
txt_move_to(text, selln, selc, 1);
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+
+ text->undo_pos++;
+ /* Scan all the stuff described in txt_undo_add_unindent_op */
+ count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ for (i = 0; i < count; i++) {
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ }
+ /* Count again */
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Get the selection and re-unindent */
+ txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ txt_unindent(text);
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2801,6 +2898,12 @@ void txt_unindent(Text *text)
int indentlen = 1;
bool unindented_first = false;
+ /* List of lines that are already at indent level 0, to store them later into the undo buffer */
+ ListBase line_index_mask = {NULL, NULL};
+ int line_index_mask_len = 0;
+ int curl_span_init = 0;
+
+
/* hardcoded: TXT_TABSIZE = 4 spaces: */
int spaceslen = TXT_TABSIZE;
@@ -2814,6 +2917,10 @@ void txt_unindent(Text *text)
indentlen = spaceslen;
}
+ if (!undoing) {
+ curl_span_init = txt_get_span(text->lines.first, text->curl);
+ }
+
while (true) {
bool changed = false;
if (STREQLEN(text->curl->line, remove, indentlen)) {
@@ -2823,6 +2930,16 @@ void txt_unindent(Text *text)
memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
changed = true;
}
+ else {
+ if (!undoing) {
+ /* Create list element for 0 indent line */
+ struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
+ idata->value = curl_span_init + num;
+ BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
+ BLI_addtail(&line_index_mask, idata);
+ line_index_mask_len += 1;
+ }
+ }
txt_make_dirty(text);
txt_clean_text(text);
@@ -2835,6 +2952,7 @@ void txt_unindent(Text *text)
else {
text->curl = text->curl->next;
num++;
+
}
}
@@ -2848,8 +2966,10 @@ void txt_unindent(Text *text)
}
if (!undoing) {
- txt_undo_add_op(text, UNDO_UNINDENT);
+ txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len);
}
+
+ BLI_freelistN(&line_index_mask);
}
void txt_comment(Text *text)
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 3293cca76fe..2ea903247b2 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -73,16 +73,16 @@
/* ****************** Mapping ******************* */
-TexMapping *add_tex_mapping(int type)
+TexMapping *BKE_texture_mapping_add(int type)
{
TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping");
- default_tex_mapping(texmap, type);
+ BKE_texture_mapping_default(texmap, type);
return texmap;
}
-void default_tex_mapping(TexMapping *texmap, int type)
+void BKE_texture_mapping_default(TexMapping *texmap, int type)
{
memset(texmap, 0, sizeof(TexMapping));
@@ -97,7 +97,7 @@ void default_tex_mapping(TexMapping *texmap, int type)
texmap->type = type;
}
-void init_tex_mapping(TexMapping *texmap)
+void BKE_texture_mapping_init(TexMapping *texmap)
{
float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];
@@ -170,16 +170,16 @@ void init_tex_mapping(TexMapping *texmap)
}
}
-ColorMapping *add_color_mapping(void)
+ColorMapping *BKE_texture_colormapping_add(void)
{
ColorMapping *colormap = MEM_callocN(sizeof(ColorMapping), "ColorMapping");
- default_color_mapping(colormap);
+ BKE_texture_colormapping_default(colormap);
return colormap;
}
-void default_color_mapping(ColorMapping *colormap)
+void BKE_texture_colormapping_default(ColorMapping *colormap)
{
memset(colormap, 0, sizeof(ColorMapping));
@@ -560,14 +560,14 @@ int colorband_element_remove(struct ColorBand *coba, int index)
void BKE_texture_free(Tex *tex)
{
if (tex->coba) MEM_freeN(tex->coba);
- if (tex->env) BKE_free_envmap(tex->env);
- if (tex->pd) BKE_free_pointdensity(tex->pd);
- if (tex->vd) BKE_free_voxeldata(tex->vd);
- if (tex->ot) BKE_free_oceantex(tex->ot);
- BKE_free_animdata((struct ID *)tex);
+ if (tex->env) BKE_texture_envmap_free(tex->env);
+ if (tex->pd) BKE_texture_pointdensity_free(tex->pd);
+ if (tex->vd) BKE_texture_voxeldata_free(tex->vd);
+ if (tex->ot) BKE_texture_ocean_free(tex->ot);
+ BKE_animdata_free((struct ID *)tex);
BKE_previewimg_free(&tex->preview);
- BKE_icon_delete((struct ID *)tex);
+ BKE_icon_id_delete((struct ID *)tex);
tex->id.icon_id = 0;
if (tex->nodetree) {
@@ -578,7 +578,7 @@ void BKE_texture_free(Tex *tex)
/* ------------------------------------------------------------------------- */
-void default_tex(Tex *tex)
+void BKE_texture_default(Tex *tex)
{
tex->type = TEX_IMAGE;
tex->ima = NULL;
@@ -629,7 +629,7 @@ void default_tex(Tex *tex)
tex->env->stype = ENV_ANIM;
tex->env->clipsta = 0.1;
tex->env->clipend = 100;
- tex->env->cuberes = 600;
+ tex->env->cuberes = 512;
tex->env->depth = 0;
}
@@ -657,25 +657,25 @@ void default_tex(Tex *tex)
tex->preview = NULL;
}
-void tex_set_type(Tex *tex, int type)
+void BKE_texture_type_set(Tex *tex, int type)
{
switch (type) {
case TEX_VOXELDATA:
if (tex->vd == NULL)
- tex->vd = BKE_add_voxeldata();
+ tex->vd = BKE_texture_voxeldata_add();
break;
case TEX_POINTDENSITY:
if (tex->pd == NULL)
- tex->pd = BKE_add_pointdensity();
+ tex->pd = BKE_texture_pointdensity_add();
break;
case TEX_ENVMAP:
if (tex->env == NULL)
- tex->env = BKE_add_envmap();
+ tex->env = BKE_texture_envmap_add();
break;
case TEX_OCEAN:
if (tex->ot == NULL)
- tex->ot = BKE_add_oceantex();
+ tex->ot = BKE_texture_ocean_add();
break;
}
@@ -684,20 +684,20 @@ void tex_set_type(Tex *tex, int type)
/* ------------------------------------------------------------------------- */
-Tex *add_texture(Main *bmain, const char *name)
+Tex *BKE_texture_add(Main *bmain, const char *name)
{
Tex *tex;
tex = BKE_libblock_alloc(bmain, ID_TE, name);
- default_tex(tex);
+ BKE_texture_default(tex);
return tex;
}
/* ------------------------------------------------------------------------- */
-void default_mtex(MTex *mtex)
+void BKE_texture_mtex_default(MTex *mtex)
{
mtex->texco = TEXCO_UV;
mtex->mapto = MAP_COL;
@@ -767,19 +767,19 @@ void default_mtex(MTex *mtex)
/* ------------------------------------------------------------------------- */
-MTex *add_mtex(void)
+MTex *BKE_texture_mtex_add(void)
{
MTex *mtex;
- mtex = MEM_callocN(sizeof(MTex), "add_mtex");
+ mtex = MEM_callocN(sizeof(MTex), "BKE_texture_mtex_add");
- default_mtex(mtex);
+ BKE_texture_mtex_default(mtex);
return mtex;
}
/* slot -1 for first free ID */
-MTex *add_mtex_id(ID *id, int slot)
+MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
MTex **mtex_ar;
short act;
@@ -820,7 +820,7 @@ MTex *add_mtex_id(ID *id, int slot)
((Material *)id)->septex &= ~(1 << slot);
}
- mtex_ar[slot] = add_mtex();
+ mtex_ar[slot] = BKE_texture_mtex_add();
return mtex_ar[slot];
}
@@ -840,10 +840,10 @@ Tex *BKE_texture_copy(Tex *tex)
}
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) texn->env = BKE_copy_envmap(texn->env);
- if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd);
+ 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_copy_oceantex(texn->ot);
+ if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot);
if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
if (tex->nodetree) {
@@ -861,7 +861,7 @@ Tex *BKE_texture_copy(Tex *tex)
}
/* texture copy without adding to main dbase */
-Tex *localize_texture(Tex *tex)
+Tex *BKE_texture_localize(Tex *tex)
{
Tex *texn;
@@ -871,17 +871,17 @@ Tex *localize_texture(Tex *tex)
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
if (texn->env) {
- texn->env = BKE_copy_envmap(texn->env);
+ texn->env = BKE_texture_envmap_copy(texn->env);
id_us_min(&texn->env->ima->id);
}
- if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd);
+ if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
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_copy_oceantex(tex->ot);
+ texn->ot = BKE_texture_ocean_copy(tex->ot);
}
texn->preview = NULL;
@@ -1132,7 +1132,7 @@ void set_current_lamp_texture(Lamp *la, Tex *newtex)
if (newtex) {
if (!la->mtex[act]) {
- la->mtex[act] = add_mtex();
+ la->mtex[act] = BKE_texture_mtex_add();
la->mtex[act]->texco = TEXCO_GLOB;
}
@@ -1167,7 +1167,7 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
if (newtex) {
if (!linestyle->mtex[act]) {
- linestyle->mtex[act] = add_mtex();
+ linestyle->mtex[act] = BKE_texture_mtex_add();
linestyle->mtex[act]->texco = TEXCO_STROKE;
}
@@ -1296,7 +1296,7 @@ void set_current_material_texture(Material *ma, Tex *newtex)
if (newtex) {
if (!ma->mtex[act]) {
- ma->mtex[act] = add_mtex();
+ ma->mtex[act] = BKE_texture_mtex_add();
/* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
ma->septex &= ~(1 << act);
}
@@ -1347,7 +1347,7 @@ void set_current_world_texture(World *wo, Tex *newtex)
if (newtex) {
if (!wo->mtex[act]) {
- wo->mtex[act] = add_mtex();
+ wo->mtex[act] = BKE_texture_mtex_add();
wo->mtex[act]->texco = TEXCO_VIEW;
}
@@ -1398,7 +1398,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
if (newtex) {
if (!part->mtex[act]) {
- part->mtex[act] = add_mtex();
+ part->mtex[act] = BKE_texture_mtex_add();
part->mtex[act]->texco = TEXCO_ORCO;
part->mtex[act]->blendtype = MTEX_MUL;
}
@@ -1414,7 +1414,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_add_envmap(void)
+EnvMap *BKE_texture_envmap_add(void)
{
EnvMap *env;
@@ -1423,7 +1423,7 @@ EnvMap *BKE_add_envmap(void)
env->stype = ENV_ANIM;
env->clipsta = 0.1;
env->clipend = 100.0;
- env->cuberes = 600;
+ env->cuberes = 512;
env->viewscale = 0.5;
return env;
@@ -1431,7 +1431,7 @@ EnvMap *BKE_add_envmap(void)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_copy_envmap(EnvMap *env)
+EnvMap *BKE_texture_envmap_copy(EnvMap *env)
{
EnvMap *envn;
int a;
@@ -1446,7 +1446,7 @@ EnvMap *BKE_copy_envmap(EnvMap *env)
/* ------------------------------------------------------------------------- */
-void BKE_free_envmapdata(EnvMap *env)
+void BKE_texture_envmap_free_data(EnvMap *env)
{
unsigned int part;
@@ -1460,17 +1460,17 @@ void BKE_free_envmapdata(EnvMap *env)
/* ------------------------------------------------------------------------- */
-void BKE_free_envmap(EnvMap *env)
+void BKE_texture_envmap_free(EnvMap *env)
{
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
MEM_freeN(env);
}
/* ------------------------------------------------------------------------- */
-PointDensity *BKE_add_pointdensity(void)
+PointDensity *BKE_texture_pointdensity_add(void)
{
PointDensity *pd;
@@ -1502,7 +1502,7 @@ PointDensity *BKE_add_pointdensity(void)
return pd;
}
-PointDensity *BKE_copy_pointdensity(PointDensity *pd)
+PointDensity *BKE_texture_pointdensity_copy(PointDensity *pd)
{
PointDensity *pdn;
@@ -1514,7 +1514,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd)
return pdn;
}
-void BKE_free_pointdensitydata(PointDensity *pd)
+void BKE_texture_pointdensity_free_data(PointDensity *pd)
{
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
@@ -1532,15 +1532,15 @@ void BKE_free_pointdensitydata(PointDensity *pd)
curvemapping_free(pd->falloff_curve); /* can be NULL */
}
-void BKE_free_pointdensity(PointDensity *pd)
+void BKE_texture_pointdensity_free(PointDensity *pd)
{
- BKE_free_pointdensitydata(pd);
+ BKE_texture_pointdensity_free_data(pd);
MEM_freeN(pd);
}
/* ------------------------------------------------------------------------- */
-void BKE_free_voxeldatadata(VoxelData *vd)
+void BKE_texture_voxeldata_free_data(VoxelData *vd)
{
if (vd->dataset) {
MEM_freeN(vd->dataset);
@@ -1549,13 +1549,13 @@ void BKE_free_voxeldatadata(VoxelData *vd)
}
-void BKE_free_voxeldata(VoxelData *vd)
+void BKE_texture_voxeldata_free(VoxelData *vd)
{
- BKE_free_voxeldatadata(vd);
+ BKE_texture_voxeldata_free_data(vd);
MEM_freeN(vd);
}
-VoxelData *BKE_add_voxeldata(void)
+VoxelData *BKE_texture_voxeldata_add(void)
{
VoxelData *vd;
@@ -1573,7 +1573,7 @@ VoxelData *BKE_add_voxeldata(void)
return vd;
}
-VoxelData *BKE_copy_voxeldata(VoxelData *vd)
+VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd)
{
VoxelData *vdn;
@@ -1585,7 +1585,7 @@ VoxelData *BKE_copy_voxeldata(VoxelData *vd)
/* ------------------------------------------------------------------------- */
-OceanTex *BKE_add_oceantex(void)
+OceanTex *BKE_texture_ocean_add(void)
{
OceanTex *ot;
@@ -1596,14 +1596,14 @@ OceanTex *BKE_add_oceantex(void)
return ot;
}
-OceanTex *BKE_copy_oceantex(struct OceanTex *ot)
+OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot)
{
OceanTex *otn = MEM_dupallocN(ot);
return otn;
}
-void BKE_free_oceantex(struct OceanTex *ot)
+void BKE_texture_ocean_free(struct OceanTex *ot)
{
MEM_freeN(ot);
}
@@ -1651,7 +1651,9 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture)
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value(Scene *scene, Tex *texture, float *tex_co, TexResult *texres, bool use_color_management)
+void BKE_texture_get_value(
+ const Scene *scene, Tex *texture,
+ float *tex_co, TexResult *texres, bool use_color_management)
{
int result_type;
bool do_color_manage = false;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 0037002f6d8..f9ae987db70 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -547,7 +547,7 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
* - If action is TRACK_CLEAR_UPTO path from the beginning up to
* ref_frame-1 will be clear.
*
- * - If action is TRACK_CLEAR_ALL only mareker at frame ref_frame will remain.
+ * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
*
* NOTE: frame number should be in clip space, not scene space
*/
@@ -730,7 +730,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT
return NULL;
}
-MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r)
+MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase)
{
MovieTrackingObject *object;
int cur = 1;
@@ -743,7 +743,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
while (track) {
if (track->flag & TRACK_HAS_BUNDLE) {
if (cur == tracknr) {
- *tracksbase_r = tracksbase;
+ *r_tracksbase = tracksbase;
return track;
}
@@ -756,7 +756,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
object = object->next;
}
- *tracksbase_r = NULL;
+ *r_tracksbase = NULL;
return NULL;
}
@@ -1302,6 +1302,95 @@ void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
}
}
+bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == track) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i, track_index;
+ MovieTrackingTrack **new_point_tracks;
+
+ if (plane_track->point_tracksnr <= 4) {
+ return false;
+ }
+
+ new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1),
+ "new point tracks array");
+
+ for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] != track) {
+ new_point_tracks[track_index++] = plane_track->point_tracks[i];
+ }
+ }
+
+ MEM_freeN(plane_track->point_tracks);
+ plane_track->point_tracks = new_point_tracks;
+ plane_track->point_tracksnr--;
+
+ return true;
+}
+
+void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *track)
+{
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = next_plane_track)
+ {
+ next_plane_track = plane_track->next;
+ if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
+ if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
+ /* Delete planes with less than 3 point tracks in it. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ }
+ }
+}
+
+void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == old_track) {
+ plane_track->point_tracks[i] = new_track;
+ break;
+ }
+ }
+}
+
+void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
+ BKE_tracking_plane_track_replace_point_track(plane_track,
+ old_track,
+ new_track);
+ }
+ }
+}
+
/*********************** Plane Marker *************************/
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 4cb3f2ca493..76261bddfbc 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -534,19 +534,9 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int track;
for (track = 0; track < context->num_tracks; ++track) {
- MovieTrackingTrack *old_track;
- bool do_update = false;
- int j;
-
- old_track = context->options[track].track;
- for (j = 0; j < plane_track->point_tracksnr; j++) {
- if (plane_track->point_tracks[j] == old_track) {
- do_update = true;
- break;
- }
- }
-
- if (do_update) {
+ if (BKE_tracking_plane_track_has_point_track(plane_track,
+ context->options[track].track))
+ {
BKE_tracking_track_plane_from_existing_motion(
plane_track,
context->first_frame);
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 882a6fabef1..56119b732fc 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -423,6 +423,7 @@ void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking,
break;
default:
BLI_assert(!"Unknown distortion model");
+ break;
}
camera_intrinsics_options->image_width = calibration_width;
@@ -454,6 +455,7 @@ void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking,
break;
default:
BLI_assert(!"Unknown distortion model");
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5a2c77b5619..0d83695d2f1 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -370,12 +370,7 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn
value_conv = value / unit->scalar;
/* Convert to a string */
- {
- len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv);
-
- if (len >= len_max)
- len = len_max;
- }
+ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
/* Add unit prefix and strip zeros */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 699e0d34161..e4736b1f54c 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -63,7 +63,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
}
BKE_previewimg_free(&wrld->preview);
- BKE_free_animdata((ID *)wrld);
+ BKE_animdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
@@ -74,7 +74,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
if (wrld->gpumaterial.first)
GPU_material_free(&wrld->gpumaterial);
- BKE_icon_delete((struct ID *)wrld);
+ BKE_icon_id_delete((struct ID *)wrld);
wrld->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 85eac1f21ed..cec455e01b9 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -50,26 +50,34 @@
/* ********************** general blender movie support ***************************** */
-static int start_stub(Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
- ReportList *UNUSED(reports))
+static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
+ ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix))
{ return 0; }
-static void end_stub(void)
+static void end_stub(void *UNUSED(context_v))
{}
-static int append_stub(RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
- int UNUSED(rectx), int UNUSED(recty), ReportList *UNUSED(reports))
+static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
+ int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports))
{ return 0; }
+static void *context_create_stub(void)
+{ return NULL; }
+
+static void context_free_stub(void *UNUSED(context_v))
+{}
+
#ifdef WITH_AVI
# include "AVI_avi.h"
/* callbacks */
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports);
-static void end_avi(void);
-static int append_avi(RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *reports);
-static void filepath_avi(char *string, RenderData *rd);
+static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix);
+static void end_avi(void *context_v);
+static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports);
+static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
+static void *context_create_avi(void);
+static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
#ifdef WITH_QUICKTIME
@@ -93,13 +101,17 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.end_movie = end_stub;
mh.get_next_frame = NULL;
mh.get_movie_path = NULL;
-
+ mh.context_create = context_create_stub;
+ mh.context_free = context_free_stub;
+
/* set the default handle, as builtin */
#ifdef WITH_AVI
mh.start_movie = start_avi;
mh.append_movie = append_avi;
mh.end_movie = end_avi;
mh.get_movie_path = filepath_avi;
+ mh.context_create = context_create_avi;
+ mh.context_free = context_free_avi;
#endif
/* do the platform specific handles */
@@ -109,6 +121,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
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
@@ -117,6 +131,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
mh.get_movie_path = BKE_ffmpeg_filepath_get;
+ mh.context_create = BKE_ffmpeg_context_create;
+ mh.context_free = BKE_ffmpeg_context_free;
}
#endif
#ifdef WITH_FRAMESERVER
@@ -125,13 +141,13 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_frameserver_append;
mh.end_movie = BKE_frameserver_end;
mh.get_next_frame = BKE_frameserver_loop;
+ mh.context_create = BKE_frameserver_context_create;
+ mh.context_free = BKE_frameserver_context_free;
}
#endif
/* in case all above are disabled */
- (void)imtype;
-
- return &mh;
+ (void)imtype;return &mh;
}
/* ****************************************************************** */
@@ -139,12 +155,21 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI
-static AviMovie *avi = NULL;
-
-static void filepath_avi(char *string, RenderData *rd)
+static void filepath_avi(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);
@@ -152,36 +177,36 @@ static void filepath_avi(char *string, RenderData *rd)
if (rd->scemode & R_EXTENSION) {
if (!BLI_testextensie(string, ".avi")) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, ".avi");
}
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
}
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports)
+static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int x, y;
char name[256];
AviFormat format;
int quality;
double framerate;
-
- (void)scene; /* unused */
-
- filepath_avi(name, rd);
+ AviMovie *avi = context_v;
+
+ filepath_avi(name, rd, preview, suffix);
x = rectx;
y = recty;
quality = rd->im_format.quality;
framerate = (double) rd->frs_sec / (double) rd->frs_sec_base;
-
- avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB;
else format = AVI_FORMAT_MJPEG;
@@ -207,12 +232,13 @@ static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportL
return 1;
}
-static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
unsigned int *rt1, *rt2, *rectot;
int x, y;
char *cp, rt;
+ AviMovie *avi = context_v;
if (avi == NULL)
return 0;
@@ -243,22 +269,37 @@ static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *p
return 1;
}
-static void end_avi(void)
+static void end_avi(void *context_v)
{
+ AviMovie *avi = context_v;
+
if (avi == NULL) return;
AVI_close_compress(avi);
- MEM_freeN(avi);
- avi = NULL;
}
+
+static void *context_create_avi(void)
+{
+ AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
+ return avi;
+}
+
+static void context_free_avi(void *context_v)
+{
+ AviMovie *avi = context_v;
+ if (avi) {
+ MEM_freeN(avi);
+ }
+}
+
#endif /* WITH_AVI */
/* similar to BKE_image_path_from_imformat() */
-void BKE_movie_filepath_get(char *string, RenderData *rd)
+void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh->get_movie_path)
- mh->get_movie_path(string, rd);
+ mh->get_movie_path(string, rd, preview, suffix);
else
string[0] = '\0';
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 128a5da9b68..af71f19c226 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -61,35 +61,38 @@
#include "ffmpeg_compat.h"
-static int ffmpeg_type = 0;
-static int ffmpeg_codec = AV_CODEC_ID_MPEG4;
-static int ffmpeg_audio_codec = AV_CODEC_ID_NONE;
-static int ffmpeg_video_bitrate = 1150;
-static int ffmpeg_audio_bitrate = 128;
-static int ffmpeg_gop_size = 12;
-static int ffmpeg_autosplit = 0;
-static int ffmpeg_autosplit_count = 0;
-
-static AVFormatContext *outfile = 0;
-static AVStream *video_stream = 0;
-static AVStream *audio_stream = 0;
-static AVFrame *current_frame = 0;
-static struct SwsContext *img_convert_ctx = 0;
-
-static uint8_t *audio_input_buffer = 0;
-static uint8_t *audio_deinterleave_buffer = 0;
-static int audio_input_samples = 0;
+typedef struct FFMpegContext {
+ int ffmpeg_type;
+ int ffmpeg_codec;
+ int ffmpeg_audio_codec;
+ int ffmpeg_video_bitrate;
+ int ffmpeg_audio_bitrate;
+ int ffmpeg_gop_size;
+ int ffmpeg_autosplit;
+ int ffmpeg_autosplit_count;
+ bool ffmpeg_preview;
+
+ AVFormatContext *outfile;
+ AVStream *video_stream;
+ AVStream *audio_stream;
+ AVFrame *current_frame;
+ struct SwsContext *img_convert_ctx;
+
+ uint8_t *audio_input_buffer;
+ uint8_t *audio_deinterleave_buffer;
+ int audio_input_samples;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
-static uint8_t *audio_output_buffer = 0;
-static int audio_outbuf_size = 0;
+ uint8_t *audio_output_buffer;
+ int audio_outbuf_size;
#endif
-static double audio_time = 0.0f;
-static bool audio_deinterleave = false;
-static int audio_sample_size = 0;
+ double audio_time;
+ bool audio_deinterleave;
+ int audio_sample_size;
#ifdef WITH_AUDASPACE
-static AUD_Device *audio_mixdown_device = 0;
+ AUD_Device *audio_mixdown_device;
#endif
+} FFMpegContext;
#define FFMPEG_AUTOSPLIT_SIZE 2000000000
@@ -98,6 +101,7 @@ static AUD_Device *audio_mixdown_device = 0;
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
static void ffmpeg_set_expert_options(RenderData *rd);
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
/* Delete a picture buffer */
@@ -116,50 +120,50 @@ static int request_float_audio_buffer(int codec_id)
}
#ifdef WITH_AUDASPACE
-static int write_audio_frame(void)
+static int write_audio_frame(FFMpegContext *context)
{
AVCodecContext *c = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
int got_output = 0;
- c = audio_stream->codec;
+ c = context->audio_stream->codec;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
- AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
- audio_time += (double) audio_input_samples / (double) c->sample_rate;
+ AUD_readDevice(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
+ context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
frame = avcodec_alloc_frame();
avcodec_get_frame_defaults(frame);
- frame->pts = audio_time / av_q2d(c->time_base);
- frame->nb_samples = audio_input_samples;
+ frame->pts = context->audio_time / av_q2d(c->time_base);
+ frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channel_layout = c->channel_layout;
#endif
- if (audio_deinterleave) {
+ if (context->audio_deinterleave) {
int channel, i;
uint8_t *temp;
for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
- memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size,
- audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size);
+ memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
+ context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
}
}
- temp = audio_deinterleave_buffer;
- audio_deinterleave_buffer = audio_input_buffer;
- audio_input_buffer = temp;
+ temp = context->audio_deinterleave_buffer;
+ context->audio_deinterleave_buffer = context->audio_input_buffer;
+ context->audio_input_buffer = temp;
}
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer,
- audio_input_samples * c->channels * audio_sample_size, 1);
+ avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
+ context->audio_input_samples * c->channels * context->audio_sample_size, 1);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet");
@@ -171,30 +175,30 @@ static int write_audio_frame(void)
return 0;
}
#else
- pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer);
+ pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
if (pkt.size < 0) {
// XXX error("Error writing audio packet");
return -1;
}
- pkt.data = audio_output_buffer;
+ pkt.data = context->audio_output_buffer;
got_output = 1;
#endif
if (got_output) {
if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_stream->time_base);
+ pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_stream->time_base);
+ pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_stream->time_base);
+ pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
- pkt.stream_index = audio_stream->index;
+ pkt.stream_index = context->audio_stream->index;
pkt.flags |= AV_PKT_FLAG_KEY;
- if (av_interleaved_write_frame(outfile, &pkt) != 0) {
+ if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame)
avcodec_free_frame(&frame);
@@ -301,11 +305,11 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
{
int got_output;
int ret, success = 1;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
AVPacket packet = { 0 };
av_init_packet(&packet);
@@ -320,22 +324,22 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
if (ret >= 0 && got_output) {
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
success = (ret == 0);
}
else if (ret < 0) {
@@ -349,11 +353,11 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
}
/* read and encode a frame of audio from the buffer */
-static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
+static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
{
uint8_t *rendered_frame;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
int width = c->width;
int height = c->height;
AVFrame *rgb_frame;
@@ -366,7 +370,7 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
}
else {
- rgb_frame = current_frame;
+ rgb_frame = context->current_frame;
}
rendered_frame = pixels;
@@ -410,17 +414,17 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
if (c->pix_fmt != PIX_FMT_BGR32) {
- sws_scale(img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
+ sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
rgb_frame->linesize, 0, c->height,
- current_frame->data, current_frame->linesize);
+ context->current_frame->data, context->current_frame->linesize);
delete_picture(rgb_frame);
}
- current_frame->format = PIX_FMT_BGR32;
- current_frame->width = width;
- current_frame->height = height;
+ context->current_frame->format = PIX_FMT_BGR32;
+ context->current_frame->width = width;
+ context->current_frame->height = height;
- return current_frame;
+ return context->current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
@@ -515,7 +519,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
/* prepare a video stream for the output file */
-static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext *of,
+static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
int rectx, int recty, char *error, int error_size)
{
AVStream *st;
@@ -541,7 +545,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->height = recty;
/* FIXME: Really bad hack (tm) for NTSC support */
- if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
+ if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
c->time_base.den = 2997;
c->time_base.num = 100;
}
@@ -554,8 +558,8 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->time_base.num = ((double) rd->frs_sec_base) * 100000;
}
- c->gop_size = ffmpeg_gop_size;
- c->bit_rate = ffmpeg_video_bitrate * 1000;
+ c->gop_size = context->ffmpeg_gop_size;
+ 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;
c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
@@ -584,7 +588,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->pix_fmt = PIX_FMT_YUV422P;
}
- if (ffmpeg_type == FFMPEG_XVID) {
+ if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */
c->pix_fmt = PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
@@ -654,14 +658,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
}
av_dict_free(&opts);
- current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+ context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
- img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
+ context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
return st;
}
-static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
+static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
{
AVStream *st;
AVCodecContext *c;
@@ -679,7 +683,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->codec_type = AVMEDIA_TYPE_AUDIO;
c->sample_rate = rd->ffcodecdata.audio_mixrate;
- c->bit_rate = ffmpeg_audio_bitrate * 1000;
+ c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->channels = rd->ffcodecdata.audio_channels;
@@ -746,35 +750,35 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
st->codec->time_base.den = st->codec->sample_rate;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+ context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
#endif
if (c->frame_size == 0)
// used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
// not sure if that is needed anymore, so let's try out if there are any
// complaints regarding some ffmpeg versions users might have
- audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
+ context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
else {
- audio_input_samples = c->frame_size;
+ context->audio_input_samples = c->frame_size;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
- audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
+ if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
+ context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
#endif
}
- audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
+ context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
- audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
+ context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
- audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
+ context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
#endif
- if (audio_deinterleave)
- audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ if (context->audio_deinterleave)
+ context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
- audio_time = 0.0f;
+ context->audio_time = 0.0f;
return st;
}
@@ -798,7 +802,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
av_dict_set(dict, key, buffer, 0);
}
-static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports)
+static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
{
/* Handle to the output file */
AVFormatContext *of;
@@ -807,26 +811,26 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
char name[256], error[1024];
const char **exts;
- ffmpeg_type = rd->ffcodecdata.type;
- ffmpeg_codec = rd->ffcodecdata.codec;
- ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
- ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
- ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
- ffmpeg_gop_size = rd->ffcodecdata.gop_size;
- ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
-
+ context->ffmpeg_type = rd->ffcodecdata.type;
+ context->ffmpeg_codec = rd->ffcodecdata.codec;
+ context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
+ context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
+ context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
+ context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
+ context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+
/* Determine the correct filename */
- BKE_ffmpeg_filepath_get(name, rd);
+ ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
PRINT("Starting output to %s(ffmpeg)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n"
" gop_size=%d, autosplit=%d\n"
" render width=%d, render height=%d\n",
- name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
- ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
- ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
+ name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
+ context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
+ context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
- exts = get_file_extensions(ffmpeg_type);
+ exts = get_file_extensions(context->ffmpeg_type);
if (!exts) {
BKE_report(reports, RPT_ERROR, "No valid formats found");
return 0;
@@ -845,7 +849,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->oformat = fmt;
of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
}
else {
@@ -856,15 +860,15 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->max_delay = (int)(0.7 * AV_TIME_BASE);
- fmt->audio_codec = ffmpeg_audio_codec;
+ fmt->audio_codec = context->ffmpeg_audio_codec;
BLI_strncpy(of->filename, name, sizeof(of->filename));
/* set the codec to the user's selection */
- switch (ffmpeg_type) {
+ switch (context->ffmpeg_type) {
case FFMPEG_AVI:
case FFMPEG_MOV:
case FFMPEG_MKV:
- fmt->video_codec = ffmpeg_codec;
+ fmt->video_codec = context->ffmpeg_codec;
break;
case FFMPEG_OGG:
fmt->video_codec = AV_CODEC_ID_THEORA;
@@ -907,9 +911,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_type == FFMPEG_DV) {
+ if (context->ffmpeg_type == FFMPEG_DV) {
fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
av_dict_free(&opts);
return 0;
@@ -917,9 +921,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
- PRINT("alloc video stream %p\n", video_stream);
- if (!video_stream) {
+ context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
+ PRINT("alloc video stream %p\n", context->video_stream);
+ if (!context->video_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -930,9 +934,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of, error, sizeof(error));
- if (!audio_stream) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
+ if (!context->audio_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -955,7 +959,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
return 0;
}
- outfile = of;
+ context->outfile = of;
av_dump_format(of, 0, name, 1);
av_dict_free(&opts);
@@ -979,11 +983,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
* parameter.
* </p>
*/
-static void flush_ffmpeg(void)
+static void flush_ffmpeg(FFMpegContext *context)
{
int ret = 0;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
/* get the delayed frames */
while (1) {
int got_output;
@@ -999,28 +1003,28 @@ static void flush_ffmpeg(void)
break;
}
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int) packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int) packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
if (ret != 0) {
fprintf(stderr, "Error writing delayed frame %d\n", ret);
break;
}
}
- avcodec_flush_buffers(video_stream->codec);
+ avcodec_flush_buffers(context->video_stream->codec);
}
/* **********************************************************************
@@ -1028,15 +1032,25 @@ static void flush_ffmpeg(void)
* ********************************************************************** */
/* Get the output filename-- similar to the other output formats */
-void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
{
char autosplit[20];
const char **exts = get_file_extensions(rd->ffcodecdata.type);
const char **fe = exts;
+ int sfra, efra;
if (!string || !exts) 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);
@@ -1045,7 +1059,9 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
autosplit[0] = 0;
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
- sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
+ if (context) {
+ sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
+ }
}
if (rd->scemode & R_EXTENSION) {
@@ -1059,7 +1075,7 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
if (*fe == NULL) {
strcat(string, autosplit);
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, *exts);
}
else {
@@ -1070,23 +1086,33 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
}
strcat(string, autosplit);
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+}
+
+void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
+{
+ ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
}
-int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports)
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int success;
+ FFMpegContext *context = context_v;
- ffmpeg_autosplit_count = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = preview;
- success = start_ffmpeg_impl(rd, rectx, recty, reports);
+ success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
#ifdef WITH_AUDASPACE
- if (audio_stream) {
- AVCodecContext *c = audio_stream->codec;
+ if (context->audio_stream) {
+ AVCodecContext *c = context->audio_stream->codec;
AUD_DeviceSpecs specs;
specs.channels = c->channels;
@@ -1111,7 +1137,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
}
specs.rate = rd->ffcodecdata.audio_mixrate;
- audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
+ context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
#ifdef FFMPEG_CODEC_TIME_BASE
c->time_base.den = specs.rate;
c->time_base.num = 1;
@@ -1121,16 +1147,16 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
return success;
}
-static void end_ffmpeg_impl(int is_autosplit);
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit);
#ifdef WITH_AUDASPACE
-static void write_audio_frames(double to_pts)
+static void write_audio_frames(FFMpegContext *context, double to_pts)
{
int finished = 0;
- while (audio_stream && !finished) {
- if ((audio_time >= to_pts) ||
- (write_audio_frame()))
+ while (context->audio_stream && !finished) {
+ if ((context->audio_time >= to_pts) ||
+ (write_audio_frame(context)))
{
finished = 1;
}
@@ -1138,8 +1164,10 @@ static void write_audio_frames(double to_pts)
}
#endif
-int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
+int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports)
{
+ FFMpegContext *context = context_v;
AVFrame *avframe;
int success = 1;
@@ -1148,111 +1176,112 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i
/* why is this done before writing the video frame and again at end_ffmpeg? */
// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
- if (video_stream) {
- avframe = generate_video_frame((unsigned char *) pixels, reports);
- success = (avframe && write_video_frame(rd, frame - start_frame, avframe, reports));
+ if (context->video_stream) {
+ avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
+ success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
- if (ffmpeg_autosplit) {
- if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
- end_ffmpeg_impl(true);
- ffmpeg_autosplit_count++;
- success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+ if (context->ffmpeg_autosplit) {
+ if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg_impl(context, true);
+ context->ffmpeg_autosplit_count++;
+ success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
#ifdef WITH_AUDASPACE
- write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+ write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
#endif
return success;
}
-static void end_ffmpeg_impl(int is_autosplit)
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
unsigned int i;
PRINT("Closing ffmpeg...\n");
#if 0
- if (audio_stream) { /* SEE UPPER */
- write_audio_frames();
+ if (context->audio_stream) { /* SEE UPPER */
+ write_audio_frames(context);
}
#endif
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
- if (audio_mixdown_device) {
- AUD_closeReadDevice(audio_mixdown_device);
- audio_mixdown_device = 0;
+ if (context->audio_mixdown_device) {
+ AUD_closeReadDevice(context->audio_mixdown_device);
+ context->audio_mixdown_device = 0;
}
}
#endif
- if (video_stream && video_stream->codec) {
+ if (context->video_stream && context->video_stream->codec) {
PRINT("Flushing delayed frames...\n");
- flush_ffmpeg();
+ flush_ffmpeg(context);
}
- if (outfile) {
- av_write_trailer(outfile);
+ if (context->outfile) {
+ av_write_trailer(context->outfile);
}
/* Close the video codec */
- if (video_stream && video_stream->codec) {
- avcodec_close(video_stream->codec);
- PRINT("zero video stream %p\n", video_stream);
- video_stream = 0;
+ if (context->video_stream && context->video_stream->codec) {
+ avcodec_close(context->video_stream->codec);
+ PRINT("zero video stream %p\n", context->video_stream);
+ context->video_stream = 0;
}
/* Close the output file */
- if (outfile) {
- for (i = 0; i < outfile->nb_streams; i++) {
- if (&outfile->streams[i]) {
- av_freep(&outfile->streams[i]);
+ if (context->outfile) {
+ for (i = 0; i < context->outfile->nb_streams; i++) {
+ if (&context->outfile->streams[i]) {
+ av_freep(&context->outfile->streams[i]);
}
}
}
/* free the temp buffer */
- if (current_frame) {
- delete_picture(current_frame);
- current_frame = 0;
+ if (context->current_frame) {
+ delete_picture(context->current_frame);
+ context->current_frame = 0;
}
- if (outfile && outfile->oformat) {
- if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
- avio_close(outfile->pb);
+ if (context->outfile && context->outfile->oformat) {
+ if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(context->outfile->pb);
}
}
- if (outfile) {
- av_free(outfile);
- outfile = 0;
+ if (context->outfile) {
+ av_free(context->outfile);
+ context->outfile = 0;
}
- if (audio_input_buffer) {
- av_free(audio_input_buffer);
- audio_input_buffer = 0;
+ if (context->audio_input_buffer) {
+ av_free(context->audio_input_buffer);
+ context->audio_input_buffer = 0;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (audio_output_buffer) {
- av_free(audio_output_buffer);
- audio_output_buffer = 0;
+ if (context->audio_output_buffer) {
+ av_free(context->audio_output_buffer);
+ context->audio_output_buffer = 0;
}
#endif
- if (audio_deinterleave_buffer) {
- av_free(audio_deinterleave_buffer);
- audio_deinterleave_buffer = 0;
+ if (context->audio_deinterleave_buffer) {
+ av_free(context->audio_deinterleave_buffer);
+ context->audio_deinterleave_buffer = 0;
}
- if (img_convert_ctx) {
- sws_freeContext(img_convert_ctx);
- img_convert_ctx = 0;
+ if (context->img_convert_ctx) {
+ sws_freeContext(context->img_convert_ctx);
+ context->img_convert_ctx = 0;
}
}
-void BKE_ffmpeg_end(void)
+void BKE_ffmpeg_end(void *context_v)
{
- end_ffmpeg_impl(false);
+ FFMpegContext *context = context_v;
+ end_ffmpeg_impl(context, false);
}
/* properties */
@@ -1646,4 +1675,31 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
return false;
}
-#endif
+void *BKE_ffmpeg_context_create(void)
+{
+ FFMpegContext *context;
+
+ /* new ffmpeg data struct */
+ context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
+
+ context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
+ context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
+ context->ffmpeg_video_bitrate = 1150;
+ context->ffmpeg_audio_bitrate = 128;
+ context->ffmpeg_gop_size = 12;
+ context->ffmpeg_autosplit = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = false;
+
+ return context;
+}
+
+void BKE_ffmpeg_context_free(void *context_v)
+{
+ FFMpegContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
+#endif /* WITH_FFMPEG */
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index ae6b19fb019..ba58038bbd8 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -66,12 +66,15 @@
#include "BKE_report.h"
#include "DNA_scene_types.h"
+#include "MEM_guardedalloc.h"
-static int sock;
-static int connsock;
-static int write_ppm;
-static int render_width;
-static int render_height;
+typedef struct FrameserverContext {
+ int sock;
+ int connsock;
+ int write_ppm;
+ int render_width;
+ int render_height;
+} FrameserverContext;
#if defined(_WIN32)
@@ -110,10 +113,11 @@ static int closesocket(int fd)
}
#endif
-int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports)
+int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
{
struct sockaddr_in addr;
int arg = 1;
+ FrameserverContext *context = context_v;
(void)scene; /* unused */
@@ -122,33 +126,33 @@ int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx
return 0;
}
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot open socket");
return 0;
}
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
+ setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
addr.sin_family = AF_INET;
addr.sin_port = htons(U.frameserverport);
addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
return 0;
}
- if (listen(sock, SOMAXCONN) < 0) {
+ if (listen(context->sock, SOMAXCONN) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
return 0;
}
- connsock = -1;
+ context->connsock = -1;
- render_width = rectx;
- render_height = recty;
+ context->render_width = rectx;
+ context->render_height = recty;
return 1;
}
@@ -177,7 +181,7 @@ static char good_bye[] =
"<body><pre>\n"
"Render stopped. Goodbye</pre></body></html>";
-static int safe_write(char *s, int tosend)
+static int safe_write(const int connsock, char *s, int tosend)
{
int total = tosend;
do {
@@ -192,12 +196,12 @@ static int safe_write(char *s, int tosend)
return total;
}
-static int safe_puts(char *s)
+static int safe_puts(const int connsock, char *s)
{
- return safe_write(s, strlen(s));
+ return safe_write(connsock, s, strlen(s));
}
-static int handle_request(RenderData *rd, char *req)
+static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
{
char *p;
char *path;
@@ -214,16 +218,16 @@ static int handle_request(RenderData *rd, char *req)
*p = 0;
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(index_page);
+ if (STREQ(path, "/index.html") || strcmp(path, "/")) {
+ safe_puts(context->connsock, index_page);
return -1;
}
- write_ppm = 0;
+ context->write_ppm = 0;
pathlen = strlen(path);
if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- write_ppm = 1;
+ context->write_ppm = 1;
return atoi(path + 12);
}
if (STREQ(path, "/info.txt")) {
@@ -241,24 +245,24 @@ static int handle_request(RenderData *rd, char *req)
"ratescale %d\n",
rd->sfra,
rd->efra,
- render_width,
- render_height,
+ context->render_width,
+ context->render_height,
rd->frs_sec,
1
);
- safe_puts(buf);
+ safe_puts(context->connsock, buf);
return -1;
}
if (STREQ(path, "/close.txt")) {
- safe_puts(good_bye);
+ safe_puts(context->connsock, good_bye);
G.is_break = true; /* Abort render */
return -1;
}
return -1;
}
-int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
+int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
{
fd_set readfds;
struct timeval tv;
@@ -271,18 +275,20 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
#endif
char buf[4096];
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
- FD_SET(sock, &readfds);
+ FD_SET(context->sock, &readfds);
- rval = select(sock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
if (rval < 0) {
return -1;
}
@@ -293,19 +299,19 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
socklen = sizeof(addr);
- if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
+ if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
return -1;
}
FD_ZERO(&readfds);
- FD_SET(connsock, &readfds);
+ FD_SET(context->connsock, &readfds);
for (;;) {
/* give 10 seconds for telnet testing... */
tv.tv_sec = 10;
tv.tv_usec = 0;
- rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
if (rval > 0) {
break;
}
@@ -319,7 +325,7 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
}
}
- len = recv(connsock, buf, sizeof(buf) - 1, 0);
+ len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
if (len < 0) {
return -1;
@@ -327,13 +333,13 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
buf[len] = 0;
- return handle_request(rd, buf);
+ return handle_request(context, rd, buf);
}
-static void serve_ppm(int *pixels, int rectx, int recty)
+static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
{
unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(render_width * 3);
+ unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
int y;
char header[1024];
@@ -348,7 +354,7 @@ static void serve_ppm(int *pixels, int rectx, int recty)
"255\n",
rectx, recty);
- safe_puts(header);
+ safe_puts(context->connsock, header);
rendered_frame = (unsigned char *)pixels;
@@ -364,36 +370,54 @@ static void serve_ppm(int *pixels, int rectx, int recty)
target += 3;
src += 4;
}
- safe_write((char *)row, 3 * rectx);
+ safe_write(context->connsock, (char *)row, 3 * rectx);
}
free(row);
- closesocket(connsock);
- connsock = -1;
+ closesocket(context->connsock);
+ context->connsock = -1;
}
-int BKE_frameserver_append(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
+ FrameserverContext *context = context_v;
+
fprintf(stderr, "Serving frame: %d\n", frame);
- if (write_ppm) {
- serve_ppm(pixels, rectx, recty);
+ if (context->write_ppm) {
+ serve_ppm(context, pixels, rectx, recty);
}
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
return 1;
}
-void BKE_frameserver_end(void)
+void BKE_frameserver_end(void *context_v)
{
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
- closesocket(sock);
+ closesocket(context->sock);
shutdown_socket_system();
}
+void *BKE_frameserver_context_create(void)
+{
+ FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
+ return context;
+}
+
+void BKE_frameserver_context_free(void *context_v)
+{
+ FrameserverContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
#endif /* WITH_FRAMESERVER */
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 0dd1439e58c..ff7976dc701 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -34,6 +34,14 @@ void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir
#define BLI_array_wrap(arr, arr_len, dir) \
_bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
+void _bli_array_permute(
+ void *arr, const unsigned int arr_len, const size_t arr_stride,
+ const unsigned int *index, void *arr_temp);
+#define BLI_array_permute(arr, arr_len, order) \
+ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
+#define BLI_array_permute_ex(arr, arr_len, index, arr_temp) \
+ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
+
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h
index b99a2534d33..5e9434a1d56 100644
--- a/source/blender/blenlib/BLI_astar.h
+++ b/source/blender/blenlib/BLI_astar.h
@@ -86,6 +86,15 @@ void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_sol
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution);
void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
+/**
+ * Callback computing the current cost (distance) to next node, and the estimated overall cost to destination node
+ * (A* expects this estimation to always be less or equal than actual shortest path from next node to destination one).
+ *
+ * \param link the graph link between current node and next one.
+ * \param node_idx_curr current node index.
+ * \param node_idx_next next node index.
+ * \param node_idx_dst destination node index.
+ */
typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link,
const int node_idx_curr, const int node_idx_next, const int node_idx_dst);
diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h
index 03b75975af4..06bbf29a223 100644
--- a/source/blender/blenlib/BLI_blenlib.h
+++ b/source/blender/blenlib/BLI_blenlib.h
@@ -58,7 +58,6 @@
#ifndef __BLI_BLENLIB_H__
#define __BLI_BLENLIB_H__
-struct ListBase;
#include <stdlib.h>
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
index 7cf524749c2..fdffbeb4c8d 100644
--- a/source/blender/blenlib/BLI_callbacks.h
+++ b/source/blender/blenlib/BLI_callbacks.h
@@ -25,7 +25,6 @@
#ifndef __BLI_CALLBACKS_H__
#define __BLI_CALLBACKS_H__
-struct bContext;
struct Main;
struct ID;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 876d2c459c5..92928889c52 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -37,7 +37,7 @@
# include <malloc.h>
#endif
-#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#if defined(__cplusplus) && ((__cplusplus >= 201103L) || defined(_MSC_VER))
# define HAS_CPP11_FEATURES
#endif
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
index 652c4a954b9..b9fb3ebf47a 100644
--- a/source/blender/blenlib/BLI_compiler_typecheck.h
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -381,4 +381,303 @@
# define CHECK_TYPE_ANY(...) (void)0
#endif
+
+/**
+ * GENERIC_TYPE_ANY: handy macro to reuse a single expression for multiple types, eg:
+ *
+ * \code{.c}
+ * _Generic(value,
+ * GENERIC_TYPE_ANY(result_a, Foo *, Bar *, Baz *),
+ * GENERIC_TYPE_ANY(result_b, Spam *, Spaz *, Spot *),
+ * )
+ * \endcode
+ *
+ * excuse ridiculously long generated args.
+ * \code{.py}
+ * for i in range(63):
+ * args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)]
+ * print("#define _VA_GENERIC_TYPE_ANY%d(r, %s) \\" % (i + 2, ", ".join(args)))
+ * print(" %s: r " % (": r, ".join(args)))
+ * \endcode
+ */
+#define _VA_GENERIC_TYPE_ANY2(r, a0) \
+ a0: r
+#define _VA_GENERIC_TYPE_ANY3(r, a0, b0) \
+ a0: r, b0: r
+#define _VA_GENERIC_TYPE_ANY4(r, a0, b0, c0) \
+ a0: r, b0: r, c0: r
+#define _VA_GENERIC_TYPE_ANY5(r, a0, b0, c0, d0) \
+ a0: r, b0: r, c0: r, d0: r
+#define _VA_GENERIC_TYPE_ANY6(r, a0, b0, c0, d0, e0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r
+#define _VA_GENERIC_TYPE_ANY7(r, a0, b0, c0, d0, e0, f0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r
+#define _VA_GENERIC_TYPE_ANY8(r, a0, b0, c0, d0, e0, f0, g0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r
+#define _VA_GENERIC_TYPE_ANY9(r, a0, b0, c0, d0, e0, f0, g0, h0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r
+#define _VA_GENERIC_TYPE_ANY10(r, a0, b0, c0, d0, e0, f0, g0, h0, i0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r
+#define _VA_GENERIC_TYPE_ANY11(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r
+#define _VA_GENERIC_TYPE_ANY12(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r
+#define _VA_GENERIC_TYPE_ANY13(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r
+#define _VA_GENERIC_TYPE_ANY14(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r
+#define _VA_GENERIC_TYPE_ANY15(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r
+#define _VA_GENERIC_TYPE_ANY16(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r
+#define _VA_GENERIC_TYPE_ANY17(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r
+#define _VA_GENERIC_TYPE_ANY18(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r
+#define _VA_GENERIC_TYPE_ANY19(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r
+#define _VA_GENERIC_TYPE_ANY20(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r
+#define _VA_GENERIC_TYPE_ANY21(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r
+#define _VA_GENERIC_TYPE_ANY22(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r
+#define _VA_GENERIC_TYPE_ANY23(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r
+#define _VA_GENERIC_TYPE_ANY24(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r
+#define _VA_GENERIC_TYPE_ANY25(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r
+#define _VA_GENERIC_TYPE_ANY26(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r
+#define _VA_GENERIC_TYPE_ANY27(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r
+#define _VA_GENERIC_TYPE_ANY28(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r
+#define _VA_GENERIC_TYPE_ANY29(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r
+#define _VA_GENERIC_TYPE_ANY30(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r
+#define _VA_GENERIC_TYPE_ANY31(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r
+#define _VA_GENERIC_TYPE_ANY32(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r
+#define _VA_GENERIC_TYPE_ANY33(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r
+#define _VA_GENERIC_TYPE_ANY34(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r
+#define _VA_GENERIC_TYPE_ANY35(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r
+#define _VA_GENERIC_TYPE_ANY36(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r
+#define _VA_GENERIC_TYPE_ANY37(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r
+#define _VA_GENERIC_TYPE_ANY38(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r
+#define _VA_GENERIC_TYPE_ANY39(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r
+#define _VA_GENERIC_TYPE_ANY40(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r
+#define _VA_GENERIC_TYPE_ANY41(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r
+#define _VA_GENERIC_TYPE_ANY42(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r
+#define _VA_GENERIC_TYPE_ANY43(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r
+#define _VA_GENERIC_TYPE_ANY44(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r
+#define _VA_GENERIC_TYPE_ANY45(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r
+#define _VA_GENERIC_TYPE_ANY46(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r
+#define _VA_GENERIC_TYPE_ANY47(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r
+#define _VA_GENERIC_TYPE_ANY48(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r
+#define _VA_GENERIC_TYPE_ANY49(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r
+#define _VA_GENERIC_TYPE_ANY50(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r
+#define _VA_GENERIC_TYPE_ANY51(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r
+#define _VA_GENERIC_TYPE_ANY52(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r
+#define _VA_GENERIC_TYPE_ANY53(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r
+#define _VA_GENERIC_TYPE_ANY54(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r
+#define _VA_GENERIC_TYPE_ANY55(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r
+#define _VA_GENERIC_TYPE_ANY56(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r
+#define _VA_GENERIC_TYPE_ANY57(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r
+#define _VA_GENERIC_TYPE_ANY58(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r
+#define _VA_GENERIC_TYPE_ANY59(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r
+#define _VA_GENERIC_TYPE_ANY60(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r
+#define _VA_GENERIC_TYPE_ANY61(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r
+#define _VA_GENERIC_TYPE_ANY62(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r
+#define _VA_GENERIC_TYPE_ANY63(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2, j2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r, j2: r
+#define _VA_GENERIC_TYPE_ANY64(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r, j2: r, k2: r
+
+# define GENERIC_TYPE_ANY(...) VA_NARGS_CALL_OVERLOAD(_VA_GENERIC_TYPE_ANY, __VA_ARGS__)
+
#endif /* __BLI_COMPILER_TYPECHECK_H__ */
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index ded4b163f71..20272dd97cd 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -54,6 +54,7 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned in
void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val_default) ATTR_WARN_UNUSED_RESULT;
void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT;
bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp);
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 7898a54002f..01aa5d39b96 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -51,7 +51,6 @@ extern "C" {
# define PATH_MAX 4096
#endif
-struct gzFile;
/* Common */
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 89dfe989a1b..43afaebac4c 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -44,8 +44,8 @@ typedef unsigned int (*GHashHashFP) (const void *key);
typedef bool (*GHashCmpFP) (const void *a, const void *b);
typedef void (*GHashKeyFreeFP) (void *key);
typedef void (*GHashValFreeFP) (void *val);
-typedef void *(*GHashKeyCopyFP) (void *key);
-typedef void *(*GHashValCopyFP) (void *val);
+typedef void *(*GHashKeyCopyFP) (const void *key);
+typedef void *(*GHashValCopyFP) (const void *val);
typedef struct GHash GHash;
@@ -58,12 +58,17 @@ typedef struct GHashIterator {
enum {
GHASH_FLAG_ALLOW_DUPES = (1 << 0), /* Only checked for in debug mode */
GHASH_FLAG_ALLOW_SHRINK = (1 << 1), /* Allow to shrink buckets' size. */
+
+#ifdef GHASH_INTERNAL_API
+ /* Internal usage only */
+ GHASH_FLAG_IS_GSET = (1 << 16), /* Whether the GHash is actually used as GSet (no value storage). */
+#endif
};
/* *** */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve, const bool store_hash) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
@@ -75,13 +80,15 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfre
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;
-bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_val, GHashKeyCopyFP keycopyfp) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
-void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
-int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT;
+unsigned int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT;
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
@@ -166,6 +173,7 @@ bool BLI_ghashutil_strcmp(const void *a, const void *b);
unsigned int BLI_ghashutil_uinthash(unsigned int key);
unsigned int BLI_ghashutil_inthash_p(const void *ptr);
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);
@@ -234,10 +242,10 @@ typedef struct GSetIterator {
} GSetIterator;
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve, const bool store_hash) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_copy(GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT;
+unsigned int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
@@ -245,7 +253,7 @@ void BLI_gset_insert(GSet *gh, void *key);
bool BLI_gset_add(GSet *gs, void *key);
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
-bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp);
+bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp,
const unsigned int nentries_reserve);
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
@@ -285,15 +293,22 @@ BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashItera
BLI_gsetIterator_done(&gs_iter_) == false; \
BLI_gsetIterator_step(&gs_iter_), i_++)
+
+/* For testing, debugging only */
+#ifdef GHASH_INTERNAL_API
int BLI_ghash_buckets_size(GHash *gh);
int BLI_gset_buckets_size(GSet *gs);
-double BLI_ghash_calc_quality(
+double BLI_ghash_calc_quality_ex(
GHash *gh, double *r_load, double *r_variance,
double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket);
-double BLI_gset_calc_quality(
+double BLI_gset_calc_quality_ex(
GSet *gs, double *r_load, double *r_variance,
double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket);
+double BLI_ghash_calc_quality(GHash *gh);
+double BLI_gset_calc_quality(GSet *gs);
+#endif /* GHASH_INTERNAL_API */
+
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 8dbf7b4a908..67cb30e8d17 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -35,45 +35,59 @@
*
*/
+#include "BLI_compiler_attrs.h"
+
struct MemArena;
struct BLI_mempool;
typedef void (*LinkNodeFreeFP)(void *link);
typedef void (*LinkNodeApplyFP)(void *link, void *userdata);
-struct LinkNode;
typedef struct LinkNode {
struct LinkNode *next;
void *link;
} LinkNode;
-int BLI_linklist_length(struct LinkNode *list);
-int BLI_linklist_index(struct LinkNode *list, void *ptr);
+/**
+ * Use for append (single linked list, storing the last element).
+ *
+ * \note list manipulation functions don't operate on this struct.
+ * This is only to be used while appending.
+ */
+typedef struct LinkNodePair {
+ LinkNode *list, *last_node;
+} LinkNodePair;
+
+int BLI_linklist_count(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
+int BLI_linklist_index(LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT;
-struct LinkNode *BLI_linklist_find(struct LinkNode *list, int index);
+LinkNode *BLI_linklist_find(LinkNode *list, int index) ATTR_WARN_UNUSED_RESULT;
-void BLI_linklist_reverse(struct LinkNode **listp);
+void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
-void BLI_linklist_move_item(struct LinkNode **listp, int curr_index, int new_index);
+void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1);
-void BLI_linklist_prepend_nlink(struct LinkNode **listp, void *ptr, struct LinkNode *nlink);
-void BLI_linklist_prepend(struct LinkNode **listp, void *ptr);
-void BLI_linklist_prepend_arena(struct LinkNode **listp, void *ptr, struct MemArena *ma);
-void BLI_linklist_prepend_pool(struct LinkNode **listp, void *ptr, struct BLI_mempool *mempool);
+void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
+void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
+void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma) ATTR_NONNULL(1, 3);
+void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool) ATTR_NONNULL(1, 3);
-void BLI_linklist_append_nlink(LinkNode **listp, void *ptr, LinkNode *nlink);
-void BLI_linklist_append(struct LinkNode **listp, void *ptr);
-void BLI_linklist_append_arena(LinkNode **listp, void *ptr, struct MemArena *ma);
-void BLI_linklist_append_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool);
+/* use LinkNodePair to avoid full search */
+void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
+void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1);
+void BLI_linklist_append_arena(LinkNodePair *list_pair, void *ptr, struct MemArena *ma) ATTR_NONNULL(1, 3);
+void BLI_linklist_append_pool(LinkNodePair *list_pair, void *ptr, struct BLI_mempool *mempool) ATTR_NONNULL(1, 3);
-void *BLI_linklist_pop(struct LinkNode **listp);
-void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool);
-void BLI_linklist_insert_after(struct LinkNode **listp, void *ptr);
+void *BLI_linklist_pop(LinkNode **listp) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void *BLI_linklist_pop_pool(LinkNode **listp, struct BLI_mempool *mempool) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+void BLI_linklist_insert_after(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
-void BLI_linklist_free(struct LinkNode *list, LinkNodeFreeFP freefunc);
-void BLI_linklist_freeN(struct LinkNode *list);
-void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool);
-void BLI_linklist_apply(struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata);
+void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc);
+void BLI_linklist_freeN(LinkNode *list);
+void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool);
+void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata);
+LinkNode *BLI_linklist_sort(LinkNode *list, int (*cmp)(const void *, const void *)) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2);
+LinkNode *BLI_linklist_sort_r(LinkNode *list, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2);
#define BLI_linklist_prepend_alloca(listp, ptr) \
BLI_linklist_prepend_nlink(listp, ptr, alloca(sizeof(LinkNode)))
diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h
index 9ac233a8fa4..a4b8f77bfa6 100644
--- a/source/blender/blenlib/BLI_linklist_stack.h
+++ b/source/blender/blenlib/BLI_linklist_stack.h
@@ -168,6 +168,16 @@
#define BLI_SMALLSTACK_IS_EMPTY(var) \
((_BLI_SMALLSTACK_CAST(var) _##var##_stack) == NULL)
+/* fill in a lookup table */
+#define BLI_SMALLSTACK_AS_TABLE(var, data) \
+{ \
+ LinkNode *_##var##_iter; \
+ unsigned int i; \
+ for (_##var##_iter = _##var##_stack, i = 0; _##var##_iter; _##var##_iter = _##var##_iter->next, i++) { \
+ (data)[i] = _BLI_SMALLSTACK_CAST(var) (_##var##_iter->link); \
+ } \
+} ((void)0)
+
/* loop over stack members last-added-first */
#define BLI_SMALLSTACK_ITER_BEGIN(var, item) \
{ \
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 2e01f743f9e..9dfa80006de 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -68,7 +68,7 @@ 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_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
-void BLI_listbase_sort_r(ListBase *listbase, void *thunk, int (*cmp)(void *, const void *, const void *)) ATTR_NONNULL(1, 3);
+void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1, 2);
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_listbase_count_ex(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h
index db2fed433da..ce0183eee68 100644
--- a/source/blender/blenlib/BLI_math.h
+++ b/source/blender/blenlib/BLI_math.h
@@ -30,18 +30,32 @@
* \ingroup bli
* \section mathabbrev Abbreviations
*
- * - fl = float
- * - db = double
- * - v2 = vec2 = vector 2
- * - v3 = vec3 = vector 3
- * - v4 = vec4 = vector 4
- * - qt = quat = quaternion
- * - dq = dquat = dual quaternion
- * - m2 = mat2 = matrix 2x2
- * - m3 = mat3 = matrix 3x3
- * - m4 = mat4 = matrix 4x4
- * - eul = euler rotation
- * - eulO = euler with order
+ * - ``fl`` = float
+ * - ``db`` = double
+ * - ``v2`` = vec2 = vector 2
+ * - ``v3`` = vec3 = vector 3
+ * - ``v4`` = vec4 = vector 4
+ * - ``vn`` = vec4 = vector N dimensions, *passed as an arg, after the vector*.
+ * - ``qt`` = quat = quaternion
+ * - ``dq`` = dquat = dual quaternion
+ * - ``m2`` = mat2 = matrix 2x2
+ * - ``m3`` = mat3 = matrix 3x3
+ * - ``m4`` = mat4 = matrix 4x4
+ * - ``eul`` = euler rotation
+ * - ``eulO`` = euler with order
+ * - ``plane`` = plane 4, (vec3, distance)
+ * - ``plane3`` = plane 3 (same as a ``plane`` with a zero 4th component)
+ *
+ * \subsection mathabbrev_all Function Type Abbreviations
+ *
+ * For non float versions of functions (which typically operate on floats),
+ * use single suffix abbreviations.
+ *
+ * - ``_d`` = double
+ * - ``_i`` = int
+ * - ``_u`` = unsigned int
+ * - ``_char`` = char
+ * - ``_uchar`` = unsigned char
*
* \section mathvarnames Variable Names
*
@@ -61,4 +75,3 @@
#include "BLI_math_interp.h"
#endif /* __BLI_MATH_H__ */
-
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index daa7db8e3cf..39c1b22a632 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -90,7 +90,7 @@ static const int NAN_INT = 0x7FC00000;
#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) && _MSC_VER >= 1800))
+#if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || defined(_MSC_VER))
#ifndef sqrtf
#define sqrtf(a) ((float)sqrt(a))
@@ -214,9 +214,7 @@ MINLINE int iroundf(float a);
MINLINE int divide_round_i(int a, int b);
MINLINE int mod_i(int i, int n);
-MINLINE unsigned int highest_order_bit_i(unsigned int n);
-MINLINE unsigned short highest_order_bit_s(unsigned short n);
-
+int pow_i(int base, int exp);
double double_round(double x, int ndigits);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
new file mode 100644
index 00000000000..876c0d92e31
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -0,0 +1,51 @@
+/*
+ * ***** 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_MATH_BITS_H__
+#define __BLI_MATH_BITS_H__
+
+/** \file BLI_math_bits.h
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_math_inline.h"
+
+MINLINE unsigned int highest_order_bit_i(unsigned int n);
+MINLINE unsigned short highest_order_bit_s(unsigned short n);
+
+#ifdef __GNUC__
+# define count_bits_i(i) __builtin_popcount(i)
+#else
+MINLINE int count_bits_i(unsigned int n);
+#endif
+
+#if BLI_MATH_DO_INLINE
+#include "intern/math_bits_inline.c"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_MATH_BITS_H__ */
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 55e57b14d09..d70dfcd9e58 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -80,13 +80,6 @@ void rgb_to_xyz(float r, float g, float b, float *x, float *y, float *z);
unsigned int rgb_to_cpack(float r, float g, float b);
unsigned int hsv_to_cpack(float h, float s, float v);
-MINLINE float rgb_to_bw(const float rgb[3]);
-MINLINE float rgb_to_grayscale(const float rgb[3]);
-MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
-MINLINE float rgb_to_luma(const float rgb[3]);
-MINLINE unsigned char rgb_to_luma_byte(const unsigned char rgb[3]);
-MINLINE float rgb_to_luma_y(const float rgb[3]);
-
/**************** Profile Transformations *****************/
float srgb_to_linearrgb(float c);
@@ -136,6 +129,9 @@ void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b);
+MINLINE float rgb_to_grayscale(const float rgb[3]);
+MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
+
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
MINLINE float dither_random_value(float s, float t);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 4f7a3310ee6..2c91aca27ef 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -102,6 +102,12 @@ float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
float dist_signed_to_plane_v3(const float p[3], const float plane[4]);
float dist_to_plane_v3(const float p[3], const float plane[4]);
+/* plane3 versions */
+float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[4]);
+float dist_squared_to_plane3_v3(const float p[3], const float plane[4]);
+float dist_signed_to_plane3_v3(const float p[3], const float plane[4]);
+float dist_to_plane3_v3(const float p[3], const float plane[4]);
+
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
@@ -142,7 +148,7 @@ int isect_line_line_v2(const float a1[2], const float a2[2], const float b1[2],
int isect_line_line_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[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]);
-int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], 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(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
int isect_line_line_epsilon_v3(
@@ -259,6 +265,7 @@ void resolve_tri_uv_v3(float r_uv[2], const float st[3], const float st0[3], con
void resolve_quad_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
void resolve_quad_uv_v2_deriv(float r_uv[2], float r_deriv[2][2],
const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
+float resolve_quad_u_v2(const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
/* use to find the point of a UV on a face */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 45972d03175..f7eeb1ec7a1 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -106,6 +106,7 @@ void mul_v2_m4v3(float r[2], float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], float M[2][2], const float v[2]);
void mul_m2v2(float M[2][2], float v[2]);
void mul_mat3_m4_v3(float M[4][4], float r[3]);
+void mul_v3_mat3_m4v3(float r[3], float M[4][4], const float v[3]);
void mul_m4_v4(float M[4][4], float r[4]);
void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]);
void mul_project_m4_v3(float M[4][4], float vec[3]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index ffd80f46725..9bc1121801e 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -146,11 +146,20 @@ MINLINE void negate_v4_v4(float r[4], const float a[3]);
MINLINE void negate_v3_short(short r[3]);
+MINLINE void abs_v2(float r[2]);
+MINLINE void abs_v2_v2(float r[2], const float a[2]);
+MINLINE void abs_v3(float r[3]);
+MINLINE void abs_v3_v3(float r[3], const float a[3]);
+MINLINE void abs_v4(float r[4]);
+MINLINE void abs_v4_v4(float r[4], const float a[4]);
+
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
@@ -264,6 +273,8 @@ void angle_poly_v3(float *angles, const float *verts[3], int len);
void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]);
void project_v3_v3v3(float r[3], const float p[3], const float n[3]);
+void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]);
+void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]);
void project_v3_plane(float v[3], const float n[3], const float p[3]);
void reflect_v3_v3v3(float r[3], const float v[3], const float n[3]);
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
@@ -299,12 +310,13 @@ void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
/***************************** Array Functions *******************************/
-/* attempted to follow fixed length vertex functions. names could be improved*/
+/* follow fixed length vector function conventions. */
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) ATTR_WARN_UNUSED_RESULT;
double len_squared_vn(const float *array, const int size) ATTR_WARN_UNUSED_RESULT;
float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
float normalize_vn(float *array_tar, const int size);
void range_vn_i(int *array_tar, const int size, const int start);
+void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start);
void range_vn_fl(float *array_tar, const int size, const float start, const float step);
void negate_vn(float *array_tar, const int size);
void negate_vn_vn(float *array_tar, const float *array_src, const int size);
@@ -319,11 +331,15 @@ void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_
void msub_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
void msub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const float f, const int size);
void interp_vn_vn(float *array_tar, const float *array_src, const float t, const int size);
-void fill_vn_i(int *array_tar, const int size, const int val);
-void fill_vn_short(short *array_tar, const int size, const short val);
-void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
-void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
-void fill_vn_fl(float *array_tar, const int size, const float val);
+void copy_vn_i(int *array_tar, const int size, const int val);
+void copy_vn_short(short *array_tar, const int size, const short val);
+void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
+void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
+void copy_vn_fl(float *array_tar, const int size, const float val);
+
+void add_vn_vn_d(double *array_tar, const double *array_src, const int size);
+void add_vn_vnvn_d(double *array_tar, const double *array_src_a, const double *array_src_b, const int size);
+void mul_vn_db(double *array_tar, const int size, const double f);
/**************************** Inline Definitions ******************************/
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index d99df24aaf7..c9a54c33f21 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -38,7 +38,6 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct ListBase;
-struct direntry;
#ifdef WIN32
#define SEP '\\'
@@ -79,6 +78,11 @@ void BLI_del_slash(char *string) ATTR_NONNULL();
const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
void BLI_path_native_slash(char *path) ATTR_NONNULL();
+#ifdef _WIN32
+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);
@@ -128,6 +132,8 @@ bool BLI_parent_dir(char *path) ATTR_NONNULL();
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
+bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
+void BLI_path_frame_strip(char *path, bool setsharp, char *ext) ATTR_NONNULL();
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
bool BLI_path_cwd(char *path) ATTR_NONNULL();
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index 82c39463dd2..eaf9c7a0738 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,14 +31,14 @@
*/
typedef struct Quadric {
- float a2, ab, ac, ad,
- b2, bc, bd,
- c2, cd,
- d2;
+ double a2, ab, ac, ad,
+ b2, bc, bd,
+ c2, cd,
+ d2;
} Quadric;
/* conversion */
-void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset);
+void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]);
void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]);
@@ -47,10 +47,10 @@ void BLI_quadric_clear(Quadric *q);
/* math */
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
-void BLI_quadric_mul(Quadric *a, const float scalar);
+void BLI_quadric_mul(Quadric *a, const double scalar);
/* solve */
-float BLI_quadric_evaluate(const Quadric *q, const float v[3]);
+double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]);
bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon);
#endif /* __BLI_QUADRIC_H__ */
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index a132ac40206..242ba9f860a 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -78,6 +78,10 @@ bool BLI_rctf_isect_x(const rctf *rect, const float x);
bool BLI_rctf_isect_y(const rctf *rect, const float y);
bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
+int BLI_rcti_length_x(const rcti *rect, const int x);
+int BLI_rcti_length_y(const rcti *rect, const int y);
+float BLI_rctf_length_x(const rctf *rect, const float x);
+float BLI_rctf_length_y(const rctf *rect, const float y);
bool BLI_rcti_isect_segment(const struct rcti *rect, const int s1[2], const int s2[2]);
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2]);
bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
@@ -89,6 +93,8 @@ 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_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
+
void print_rctf(const char *str, const struct rctf *rect);
void print_rcti(const char *str, const struct rcti *rect);
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index a8c4478c450..222005ee92e 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -44,10 +44,12 @@ void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL();
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
+void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index 864a7704aa9..2d8d6e4482d 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -40,7 +40,7 @@
# define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off)
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b)
#endif
-#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert(index >= 0 && index < _##stack##_index))
+#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)index < _##stack##_index))
#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index c4853e37398..c8491f4c8f1 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -59,8 +59,10 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
size_t BLI_vsnprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg) ATTR_PRINTF_FORMAT(3, 0);
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
@@ -88,9 +90,11 @@ int BLI_str_index_in_array(const char *__restrict str, const char **__restrict s
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL();
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length) ATTR_NONNULL();
-size_t BLI_str_partition(const char *str, const char delim[], char **sep, char **suf) ATTR_NONNULL();
-size_t BLI_str_rpartition(const char *str, const char delim[], char **sep, char **suf) ATTR_NONNULL();
-size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, char **suf, const bool from_right) ATTR_NONNULL();
+size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf) ATTR_NONNULL();
+size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf) ATTR_NONNULL();
+size_t BLI_str_partition_ex(
+ const char *str, const char *end, const char delim[], const char **sep, const char **suf, const bool from_right)
+ ATTR_NONNULL(1, 3, 4, 5);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 3e599865416..0740b574c1a 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -67,9 +67,11 @@ int BLI_wcswidth(const wchar_t *pwcs, size_t n) ATTR_NONNULL();
int BLI_str_utf8_char_width(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */
int BLI_str_utf8_char_width_safe(const char *p) ATTR_NONNULL();
-size_t BLI_str_partition_utf8(const char *str, const unsigned int delim[], char **sep, char **suf) ATTR_NONNULL();
-size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], char **sep, char **suf) ATTR_NONNULL();
-size_t BLI_str_partition_ex_utf8(const char *str, const unsigned int delim[], char **sep, char **suf, const bool from_right) ATTR_NONNULL();
+size_t BLI_str_partition_utf8(const char *str, const unsigned int delim[], const char **sep, const char **suf) ATTR_NONNULL();
+size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], const char **sep, const char **suf) ATTR_NONNULL();
+size_t BLI_str_partition_ex_utf8(
+ const char *str, const char *end, const unsigned int delim[], const char **sep, const char **suf, const bool from_right)
+ ATTR_NONNULL(1, 3, 4, 5);
#define BLI_UTF8_MAX 6 /* mem */
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 2eaec024ce2..780b0bfbbd6 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -88,6 +88,9 @@ 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);
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 74291ca305e..b2ead15af22 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -89,6 +89,7 @@ int BLI_system_num_threads_override_get(void);
#define LOCK_MOVIECLIP 7
#define LOCK_COLORMANAGE 8
#define LOCK_FFTW 9
+#define LOCK_VIEW3D 10
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);
@@ -174,6 +175,7 @@ void BLI_thread_queue_push(ThreadQueue *queue, void *work);
void *BLI_thread_queue_pop(ThreadQueue *queue);
void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms);
int BLI_thread_queue_size(ThreadQueue *queue);
+bool BLI_thread_queue_is_empty(ThreadQueue *queue);
void BLI_thread_queue_wait_finish(ThreadQueue *queue);
void BLI_thread_queue_nowait(ThreadQueue *queue);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 1e8440e55e9..8f2f906ed17 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -252,7 +252,7 @@ extern "C" {
#define FTOCHAR(val) ((CHECK_TYPE_INLINE(val, float)), \
(char)(((val) <= 0.0f) ? 0 : (((val) > (1.0f - 0.5f / 255.0f)) ? 255 : ((255.0f * (val)) + 0.5f))))
#define FTOUSHORT(val) ((CHECK_TYPE_INLINE(val, float)), \
- ((val >= 1.0f - 0.5f / 65535) ? 65535 : (val <= 0.0f) ? 0 : (unsigned short)(val * 65535.0f + 0.5f)))
+ (unsigned short)((val >= 1.0f - 0.5f / 65535) ? 65535 : (val <= 0.0f) ? 0 : (val * 65535.0f + 0.5f)))
#define USHORTTOUCHAR(val) ((unsigned char)(((val) >= 65535 - 128) ? 255 : ((val) + 128) >> 8))
#define F3TOCHAR3(v2, v1) { \
(v1)[0] = FTOCHAR((v2[0])); \
@@ -435,7 +435,7 @@ extern "C" {
} (void)0
/* assuming a static array */
-#if defined(__GNUC__) && !defined(__cplusplus)
+#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__)
# define ARRAY_SIZE(arr) \
((sizeof(struct {int isnt_array : ((const void *)&(arr) == &(arr)[0]);}) * 0) + \
(sizeof(arr) / sizeof(*(arr))))
@@ -493,8 +493,11 @@ extern "C" {
#define OFFSETOF_STRUCT(_struct, _member) \
((((char *)&((_struct)->_member)) - ((char *)(_struct))) + sizeof((_struct)->_member))
-/* memcpy, skipping the first part of a struct,
- * ensures 'struct_dst' isn't const and that the offset can be computed at compile time */
+/**
+ * memcpy helper, skipping the first part of a struct,
+ * ensures 'struct_dst' isn't const and the offset can be computed at compile time.
+ * This isn't inclusive, the value of \a member isn't copied.
+ */
#define MEMCPY_STRUCT_OFS(struct_dst, struct_src, member) { \
CHECK_TYPE_NONCONST(struct_dst); \
((void)(struct_dst == struct_src), \
@@ -503,6 +506,13 @@ extern "C" {
sizeof(*(struct_dst)) - OFFSETOF_STRUCT(struct_dst, member))); \
} (void)0
+#define MEMSET_STRUCT_OFS(struct_var, value, member) { \
+ CHECK_TYPE_NONCONST(struct_var); \
+ memset((char *)(struct_var) + OFFSETOF_STRUCT(struct_var, member), \
+ value, \
+ sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member)); \
+} (void)0
+
/* Warning-free macros for storing ints in pointers. Use these _only_
* for storing an int in a pointer, not a pointer in an int (64bit)! */
#define SET_INT_IN_POINTER(i) ((void *)(intptr_t)(i))
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index f40359ec3dc..8cf6f188e19 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -132,17 +132,8 @@ struct dirent {
char *d_name;
};
-typedef struct _DIR {
- HANDLE handle;
- WIN32_FIND_DATAW data;
- char path[MAX_PATH];
- long dd_loc;
- long dd_size;
- char dd_buf[4096];
- void *dd_direct;
-
- struct dirent direntry;
-} DIR;
+/* intentionally opaque to users */
+typedef struct __dirstream DIR;
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dp);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e614a2a0663..37c9afd3a6d 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -23,8 +23,6 @@
#
# ***** END GPL LICENSE BLOCK *****
-# XXX allowing blenkernel and RNA includes in blenlib is a hack,
-# but needed in a few places atm (bpath.c for instance)
set(INC
.
# ../blenkernel # dont add this back!
@@ -44,6 +42,7 @@ set(SRC
intern/BLI_array.c
intern/BLI_dial.c
intern/BLI_dynstr.c
+ intern/BLI_filelist.c
intern/BLI_ghash.c
intern/BLI_heap.c
intern/BLI_kdopbvh.c
@@ -71,9 +70,11 @@ set(SRC
intern/hash_mm2a.c
intern/jitter.c
intern/lasso.c
+ intern/list_sort_impl.h
intern/listbase.c
intern/math_base.c
intern/math_base_inline.c
+ intern/math_bits_inline.c
intern/math_color.c
intern/math_color_blend_inline.c
intern/math_color_inline.c
@@ -153,6 +154,7 @@ set(SRC
BLI_listbase.h
BLI_math.h
BLI_math_base.h
+ BLI_math_bits.h
BLI_math_color.h
BLI_math_color_blend.h
BLI_math_geom.h
@@ -205,10 +207,15 @@ if(WIN32)
)
endif()
-blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}")
+# no need to compile object files for inline headers.
+set_source_files_properties(
+ intern/math_base_inline.c
+ intern/math_bits_inline.c
+ intern/math_color_blend_inline.c
+ intern/math_color_inline.c
+ intern/math_geom_inline.c
+ intern/math_vector_inline.c
+ PROPERTIES HEADER_FILE_ONLY TRUE
+)
-if(MSVC)
- # Quiet warning about inline math library files that do not export symbols.
- # (normally you'd exclude from project, but we still want to see the files in MSVC)
- set_target_properties(bf_blenlib PROPERTIES STATIC_LIBRARY_FLAGS /ignore:4221)
-endif()
+blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 8617132e988..80cbce7e256 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -258,11 +258,11 @@ int BLI_dynstr_get_len(DynStr *ds)
/**
* Get a DynStr's contents as a c-string.
- * <i> The str argument must be allocated to be at
- * least the size of BLI_dynstr_get_len(ds) + 1. </i>
+ * he \a rets argument must be allocated to be at
+ * least the size of ``BLI_dynstr_get_len(ds) + 1``.
*
- * \param ds The DynStr of interest.
- * \param str The string to fill.
+ * \param ds: The DynStr of interest.
+ * \param rets: The string to fill.
*/
void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict rets)
{
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
new file mode 100644
index 00000000000..786eaa74df8
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -0,0 +1,392 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/BLI_filelist.c
+ * \ingroup bli
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef WIN32
+# include <dirent.h>
+#endif
+
+#include <time.h>
+#include <sys/stat.h>
+#include <string.h> /* strcpy etc.. */
+
+#ifdef WIN32
+# include <io.h>
+# include <direct.h>
+# include "BLI_winstuff.h"
+# include "utfconv.h"
+#else
+# include <sys/ioctl.h>
+# include <unistd.h>
+# include <pwd.h>
+#endif
+
+/* lib includes */
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_path_util.h"
+
+#include "../imbuf/IMB_imbuf.h"
+
+
+/*
+ * Ordering function for sorting lists of files/directories. Returns -1 if
+ * entry1 belongs before entry2, 0 if they are equal, 1 if they should be swapped.
+ */
+static int bli_compare(struct direntry *entry1, struct direntry *entry2)
+{
+ /* type is equal to stat.st_mode */
+
+ /* directories come before non-directories */
+ if (S_ISDIR(entry1->type)) {
+ if (S_ISDIR(entry2->type) == 0) return (-1);
+ }
+ else {
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ /* non-regular files come after regular files */
+ if (S_ISREG(entry1->type)) {
+ if (S_ISREG(entry2->type) == 0) return (-1);
+ }
+ else {
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ /* arbitrary, but consistent, ordering of different types of non-regular files */
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
+ /* make sure "." and ".." are always first */
+ if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
+ if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_PARENT(entry2->relname)) return (1);
+
+ return (BLI_natstrcmp(entry1->relname, entry2->relname));
+}
+
+
+struct BuildDirCtx {
+ struct direntry *files; /* array[nrfiles] */
+ int nrfiles;
+};
+
+/**
+ * Scans the directory named *dirname and appends entries for its contents to files.
+ */
+static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
+{
+ struct ListBase dirbase = {NULL, NULL};
+ int newnum = 0;
+ DIR *dir;
+
+ if ((dir = opendir(dirname)) != NULL) {
+ const struct dirent *fname;
+ bool has_current = false, has_parent = false;
+
+ while ((fname = readdir(dir)) != NULL) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(fname->d_name);
+ if (FILENAME_IS_PARENT(dlink->name)) {
+ has_parent = true;
+ }
+ else if (FILENAME_IS_CURRENT(dlink->name)) {
+ has_current = true;
+ }
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+
+ if (!has_parent) {
+ char pardir[FILE_MAXDIR];
+
+ BLI_strncpy(pardir, dirname, sizeof(pardir));
+ if (BLI_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(FILENAME_PARENT);
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+ }
+ if (!has_current) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(FILENAME_CURRENT);
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+
+ if (newnum) {
+ if (dir_ctx->files) {
+ void * const tmp = MEM_reallocN(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
+ if (tmp) {
+ dir_ctx->files = (struct direntry *)tmp;
+ }
+ else { /* realloc fail */
+ MEM_freeN(dir_ctx->files);
+ dir_ctx->files = NULL;
+ }
+ }
+
+ if (dir_ctx->files == NULL)
+ dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry), __func__);
+
+ if (dir_ctx->files) {
+ struct dirlink * dlink = (struct dirlink *) dirbase.first;
+ struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
+ while (dlink) {
+ char fullname[PATH_MAX];
+ memset(file, 0, sizeof(struct direntry));
+ file->relname = dlink->name;
+ file->path = BLI_strdupcat(dirname, dlink->name);
+ BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
+ if (BLI_stat(fullname, &file->s) != -1) {
+ file->type = file->s.st_mode;
+ }
+ else if (FILENAME_IS_CURRPAR(file->relname)) {
+ /* Hack around for UNC paths on windows - does not support stat on '\\SERVER\foo\..', sigh... */
+ file->type |= S_IFDIR;
+ }
+ file->flags = 0;
+ dir_ctx->nrfiles++;
+ file++;
+ dlink = dlink->next;
+ }
+ }
+ else {
+ printf("Couldn't get memory for dir\n");
+ exit(1);
+ }
+
+ BLI_freelist(&dirbase);
+ if (dir_ctx->files) {
+ qsort(dir_ctx->files, dir_ctx->nrfiles, sizeof(struct direntry), (int (*)(const void *, const void *))bli_compare);
+ }
+ }
+ else {
+ printf("%s empty directory\n", dirname);
+ }
+
+ closedir(dir);
+ }
+ else {
+ printf("%s non-existent directory\n", dirname);
+ }
+}
+
+/**
+ * Fills in the "mode[123]", "size" and "string" fields in the elements of the files
+ * array with descriptive details about each item. "string" will have a format similar to "ls -l".
+ */
+static void bli_adddirstrings(struct BuildDirCtx *dir_ctx)
+{
+ const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
+ /* symbolic display, indexed by mode field value */
+ int num;
+ double size;
+ struct direntry *file;
+ struct tm *tm;
+ time_t zero = 0;
+
+#ifndef WIN32
+ int mode;
+#endif
+
+ for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) {
+
+ /* Mode */
+#ifdef WIN32
+ BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
+ BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
+ BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
+#else
+ mode = file->s.st_mode;
+
+ BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
+ BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
+ BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
+
+ if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l';
+
+ if (mode & (S_ISUID | S_ISGID)) {
+ if (file->mode1[2] == 'x') file->mode1[2] = 's';
+ else file->mode1[2] = 'S';
+
+ if (file->mode2[2] == 'x') file->mode2[2] = 's';
+ }
+
+ if (mode & S_ISVTX) {
+ if (file->mode3[2] == 'x') file->mode3[2] = 't';
+ else file->mode3[2] = 'T';
+ }
+#endif
+
+
+ /* User */
+#ifdef WIN32
+ strcpy(file->owner, "user");
+#else
+ {
+ struct passwd *pwuser;
+ pwuser = getpwuid(file->s.st_uid);
+ if (pwuser) {
+ BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
+ }
+ else {
+ BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid);
+ }
+ }
+#endif
+
+
+ /* Time */
+ tm = localtime(&file->s.st_mtime);
+ // prevent impossible dates in windows
+ if (tm == NULL) tm = localtime(&zero);
+ strftime(file->time, sizeof(file->time), "%H:%M", tm);
+ strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
+
+
+ /* Size */
+ /*
+ * Seems st_size is signed 32-bit value in *nix and Windows. This
+ * will buy us some time until files get bigger than 4GB or until
+ * everyone starts using __USE_FILE_OFFSET64 or equivalent.
+ */
+ size = (double)file->s.st_size;
+
+ if (size > 1024.0 * 1024.0 * 1024.0 * 1024.0) {
+ BLI_snprintf(file->size, sizeof(file->size), "%.1f TiB", size / (1024.0 * 1024.0 * 1024.0 * 1024.0));
+ }
+ else if (size > 1024.0 * 1024.0 * 1024.0) {
+ BLI_snprintf(file->size, sizeof(file->size), "%.1f GiB", size / (1024.0 * 1024.0 * 1024.0));
+ }
+ else if (size > 1024.0 * 1024.0) {
+ BLI_snprintf(file->size, sizeof(file->size), "%.1f MiB", size / (1024.0 * 1024.0));
+ }
+ else if (size > 1024.0) {
+ BLI_snprintf(file->size, sizeof(file->size), "%.1f KiB", size / 1024.0);
+ }
+ else {
+ BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)size);
+ }
+ }
+}
+
+/**
+ * Scans the contents of the directory named *dirname, and allocates and fills in an
+ * array of entries describing them in *filelist.
+ *
+ * \return The length of filelist array.
+ */
+unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist)
+{
+ struct BuildDirCtx dir_ctx;
+
+ dir_ctx.nrfiles = 0;
+ dir_ctx.files = NULL;
+
+ bli_builddir(&dir_ctx, dirname);
+ bli_adddirstrings(&dir_ctx);
+
+ if (dir_ctx.files) {
+ *filelist = dir_ctx.files;
+ }
+ else {
+ // keep blender happy. Blender stores this in a variable
+ // where 0 has special meaning.....
+ *filelist = MEM_mallocN(sizeof(**filelist), __func__);
+ }
+
+ return dir_ctx.nrfiles;
+}
+
+/**
+ * Deep-duplicate of an array of direntries, including the array itself.
+ *
+ * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
+ */
+void BLI_filelist_duplicate(
+ struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
+ void *(*dup_poin)(void *))
+{
+ unsigned int i;
+
+ *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
+ for (i = 0; i < nrentries; ++i) {
+ struct direntry * const src = &src_filelist[i];
+ struct direntry *dest = &(*dest_filelist)[i];
+ *dest = *src;
+ if (dest->image) {
+ dest->image = IMB_dupImBuf(src->image);
+ }
+ if (dest->relname) {
+ dest->relname = MEM_dupallocN(src->relname);
+ }
+ if (dest->path) {
+ dest->path = MEM_dupallocN(src->path);
+ }
+ if (dest->poin && dup_poin) {
+ dest->poin = dup_poin(src->poin);
+ }
+ }
+}
+
+/**
+ * frees storage for an array of direntries, including the array itself.
+ */
+void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *))
+{
+ unsigned int i;
+ for (i = 0; i < nrentries; ++i) {
+ struct direntry *entry = filelist + i;
+ if (entry->image) {
+ IMB_freeImBuf(entry->image);
+ }
+ if (entry->relname)
+ MEM_freeN(entry->relname);
+ if (entry->path)
+ MEM_freeN(entry->path);
+ if (entry->poin && free_poin)
+ free_poin(entry->poin);
+ }
+
+ if (filelist != NULL) {
+ MEM_freeN(filelist);
+ }
+}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index ff5c20f9c47..f6f203cc1ef 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -45,11 +45,12 @@
#include "BLI_utildefines.h"
#include "BLI_hash_mm2a.h"
#include "BLI_mempool.h"
+
+#define GHASH_INTERNAL_API
#include "BLI_ghash.h"
#include "BLI_strict_flags.h"
#define GHASH_USE_MODULO_BUCKETS
-#define GHASH_STORE_HASH store_hash /* For testing only (allows forcing true/false), will be removed before master! */
/* Also used by smallhash! */
const unsigned int hashsizes[] = {
@@ -66,8 +67,15 @@ const unsigned int hashsizes[] = {
# define GHASH_BUCKET_BIT_MAX 28 /* About 268M of buckets... */
#endif
-#define GHASH_LIMIT_GROW(_nbkt) ((_nbkt) * 3) / 4
-#define GHASH_LIMIT_SHRINK(_nbkt) ((_nbkt) * 3) / 16
+/**
+ * \note Max load #GHASH_LIMIT_GROW used to be 3. (pre 2.74).
+ * Python uses 0.6666, tommyhaslib even goes down to 0.5.
+ * Reducing our from 3 to 0.75 gives huge speedup (about twice quicker pure GHash insertions/lookup,
+ * about 25% - 30% quicker 'dynamic-topology' stroke drawing e.g.).
+ * Min load #GHASH_LIMIT_SHRINK is a quarter of max load, to avoid resizing to quickly.
+ */
+#define GHASH_LIMIT_GROW(_nbkt) (((_nbkt) * 3) / 4)
+#define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt) * 3) / 16)
/***/
@@ -84,25 +92,10 @@ typedef struct GHashEntry {
void *val;
} GHashEntry;
-typedef struct GHashEntryHash {
- Entry e;
-
- void *val;
- unsigned int hash; /* Order is very important here! */
-} GHashEntryHash;
-
typedef Entry GSetEntry;
-typedef struct GSetEntryHash {
- Entry e;
-
- unsigned int hash;
-} GSetEntryHash;
-
-#define GHASH_ENTRY_SIZE(_is_gset, _use_hash) \
- (_is_gset) ? \
- ((_use_hash) ? sizeof(GSetEntryHash) : sizeof(GSetEntry)) : \
- ((_use_hash) ? sizeof(GHashEntryHash) : sizeof(GHashEntry))
+#define GHASH_ENTRY_SIZE(_is_gset) \
+ ((_is_gset) ? sizeof(GSetEntry) : sizeof(GHashEntry))
struct GHash {
GHashHashFP hashfp;
@@ -119,37 +112,23 @@ struct GHash {
#endif
unsigned int nentries;
- unsigned short flag;
- bool is_gset;
- bool use_store_hash;
+ unsigned int flag;
};
-BLI_INLINE void entry_copy(
+BLI_INLINE void ghash_entry_copy(
GHash *gh_dst, Entry *dst, GHash *gh_src, Entry *src,
- const unsigned int hash, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
+ GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
{
- const bool is_gset_dst = gh_dst->is_gset;
- const bool is_gset_src = gh_src->is_gset;
-
dst->key = (keycopyfp) ? keycopyfp(src->key) : src->key;
- if (gh_dst->use_store_hash) {
- if (is_gset_dst) {
- ((GSetEntryHash *)dst)->hash = hash;
+ if ((gh_dst->flag & GHASH_FLAG_IS_GSET) == 0) {
+ if ((gh_src->flag & GHASH_FLAG_IS_GSET) == 0) {
+ ((GHashEntry *)dst)->val = (valcopyfp) ? valcopyfp(((GHashEntry *)src)->val) : ((GHashEntry *)src)->val;
}
else {
- ((GHashEntryHash *)dst)->hash = hash;
- }
- }
-
- if (!is_gset_dst) {
- if (is_gset_src) {
((GHashEntry *)dst)->val = NULL;
}
- else {
- ((GHashEntry *)dst)->val = (valcopyfp) ? valcopyfp(((GHashEntry *)src)->val) : ((GHashEntry *)src)->val;
- }
}
}
@@ -172,25 +151,25 @@ BLI_INLINE unsigned int ghash_keyhash(GHash *gh, const void *key)
*/
BLI_INLINE unsigned int ghash_entryhash(GHash *gh, const Entry *e)
{
- return gh->use_store_hash ? (gh->is_gset ? ((GSetEntryHash *)e)->hash : ((GHashEntryHash *)e)->hash) : gh->hashfp(e->key);
+ return gh->hashfp(e->key);
}
/**
* Get the bucket-hash for an already-computed full hash.
*/
-BLI_INLINE unsigned int ghash_bucket_hash(GHash *gh, const unsigned int full_hash)
+BLI_INLINE unsigned int ghash_bucket_index(GHash *gh, const unsigned int hash)
{
#ifdef GHASH_USE_MODULO_BUCKETS
- return full_hash % gh->nbuckets;
+ return hash % gh->nbuckets;
#else
- return full_hash & gh->bucket_mask;
+ return hash & gh->bucket_mask;
#endif
}
/**
* Expand buckets to the next size up or down.
*/
-BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
+static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
{
Entry **buckets_old = gh->buckets;
Entry **buckets_new;
@@ -215,10 +194,10 @@ BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
Entry *e_next;
for (e = buckets_old[i]; e; e = e_next) {
const unsigned hash = ghash_entryhash(gh, e);
- const unsigned bucket_hash = ghash_bucket_hash(gh, hash);
+ const unsigned bucket_index = ghash_bucket_index(gh, hash);
e_next = e->next;
- e->next = buckets_new[bucket_hash];
- buckets_new[bucket_hash] = e;
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = e;
}
}
}
@@ -228,20 +207,20 @@ BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
Entry *e_next;
for (e = buckets_old[i]; e; e = e_next) {
const unsigned hash = ghash_entryhash(gh, e);
- const unsigned bucket_hash = ghash_bucket_hash(gh, hash);
+ const unsigned bucket_index = ghash_bucket_index(gh, hash);
e_next = e->next;
- e->next = buckets_new[bucket_hash];
- buckets_new[bucket_hash] = e;
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = e;
}
#else
/* No need to recompute hashes in this case, since our mask is just smaller, all items in old bucket i
* will go in same new bucket (i & new_mask)! */
- const unsigned bucket_hash = ghash_bucket_hash(gh, i);
- BLI_assert(!buckets_old[i] || (bucket_hash == ghash_bucket_hash(gh, ghash_entryhash(gh, buckets_old[i]))));
+ const unsigned bucket_index = ghash_bucket_index(gh, i);
+ BLI_assert(!buckets_old[i] || (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i]))));
for (e = buckets_old[i]; e && e->next; e = e->next);
if (e) {
- e->next = buckets_new[bucket_hash];
- buckets_new[bucket_hash] = buckets_old[i];
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = buckets_old[i];
}
#endif
}
@@ -261,44 +240,81 @@ BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
* Check if the number of items in the GHash is large enough to require more buckets,
* or small enough to require less buckets, and resize \a gh accordingly.
*/
-BLI_INLINE void ghash_expand_buckets(
- GHash *gh, const unsigned int nentries, const bool user_defined, const bool force_shrink)
+static void ghash_buckets_expand(
+ GHash *gh, const unsigned int nentries, const bool user_defined)
{
unsigned int new_nbuckets;
- if (LIKELY(gh->buckets && (nentries < gh->limit_grow) && (nentries > gh->limit_shrink))) {
+ if (LIKELY(gh->buckets && (nentries < gh->limit_grow))) {
return;
}
new_nbuckets = gh->nbuckets;
- while ((nentries > gh->limit_grow) &&
#ifdef GHASH_USE_MODULO_BUCKETS
+ while ((nentries > gh->limit_grow) &&
(gh->cursize < GHASH_MAX_SIZE - 1))
{
new_nbuckets = hashsizes[++gh->cursize];
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ }
#else
+ while ((nentries > gh->limit_grow) &&
(gh->bucket_bit < GHASH_BUCKET_BIT_MAX))
{
new_nbuckets = 1u << ++gh->bucket_bit;
-#endif
gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
}
- if (force_shrink || (gh->flag & GHASH_FLAG_ALLOW_SHRINK)) {
- while ((nentries < gh->limit_shrink) &&
+#endif
+
+ if (user_defined) {
#ifdef GHASH_USE_MODULO_BUCKETS
- (gh->cursize > gh->size_min))
- {
- new_nbuckets = hashsizes[--gh->cursize];
+ gh->size_min = gh->cursize;
#else
- (gh->bucket_bit > gh->bucket_bit_min))
- {
- new_nbuckets = 1u << --gh->bucket_bit;
+ gh->bucket_bit_min = gh->bucket_bit;
#endif
- gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
- }
}
+ if ((new_nbuckets == gh->nbuckets) && gh->buckets) {
+ return;
+ }
+
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ ghash_buckets_resize(gh, new_nbuckets);
+}
+
+static void ghash_buckets_contract(
+ GHash *gh, const unsigned int nentries, const bool user_defined, const bool force_shrink)
+{
+ unsigned int new_nbuckets;
+
+ if (!(force_shrink || (gh->flag & GHASH_FLAG_ALLOW_SHRINK))) {
+ return;
+ }
+
+ if (LIKELY(gh->buckets && (nentries > gh->limit_shrink))) {
+ return;
+ }
+
+ new_nbuckets = gh->nbuckets;
+
+#ifdef GHASH_USE_MODULO_BUCKETS
+ while ((nentries < gh->limit_shrink) &&
+ (gh->cursize > gh->size_min))
+ {
+ new_nbuckets = hashsizes[--gh->cursize];
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ }
+#else
+ while ((nentries < gh->limit_shrink) &&
+ (gh->bucket_bit > gh->bucket_bit_min))
+ {
+ new_nbuckets = 1u << --gh->bucket_bit;
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ }
+#endif
+
if (user_defined) {
#ifdef GHASH_USE_MODULO_BUCKETS
gh->size_min = gh->cursize;
@@ -311,10 +327,9 @@ BLI_INLINE void ghash_expand_buckets(
return;
}
- gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
-// TIMEIT_BENCH(ghash_resize_buckets(gh, new_nbuckets), ghash_resize_buckets);
- ghash_resize_buckets(gh, new_nbuckets);
+ ghash_buckets_resize(gh, new_nbuckets);
}
/**
@@ -335,99 +350,53 @@ BLI_INLINE void ghash_buckets_reset(GHash *gh, const unsigned int nentries)
gh->bucket_mask = gh->nbuckets - 1;
#endif
- gh->limit_grow = GHASH_LIMIT_GROW(gh->nbuckets);
+ gh->limit_grow = GHASH_LIMIT_GROW(gh->nbuckets);
gh->limit_shrink = GHASH_LIMIT_SHRINK(gh->nbuckets);
gh->nentries = 0;
- gh->flag = 0;
- ghash_expand_buckets(gh, nentries, (nentries != 0), false);
+ ghash_buckets_expand(gh, nentries, (nentries != 0));
}
/**
* Internal lookup function.
- * Takes hash and bucket_hash arguments to avoid calling #ghash_keyhash and #ghash_bucket_hash multiple times.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
*/
BLI_INLINE Entry *ghash_lookup_entry_ex(
- GHash *gh, const void *key, const unsigned int hash, const unsigned int bucket_hash)
-{
- if (gh->use_store_hash) {
- if (gh->is_gset) {
- GSetEntryHash *e;
- for (e = (GSetEntryHash *)gh->buckets[bucket_hash]; e; e = (GSetEntryHash *)e->e.next) {
- if (UNLIKELY(e->hash == hash)) {
- if (LIKELY(gh->cmpfp(key, e->e.key) == false)) {
- return (Entry *)e;
- }
- }
- }
- }
- else {
- GHashEntryHash *e;
- for (e = (GHashEntryHash *)gh->buckets[bucket_hash]; e; e = (GHashEntryHash *)e->e.next) {
- if (UNLIKELY(e->hash == hash)) {
- if (LIKELY(gh->cmpfp(key, e->e.key) == false)) {
- return (Entry *)e;
- }
- }
- }
- }
- }
- else {
- Entry *e;
- /* If we do not store GHash, not worth computing it for each entry here!
- * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
- for (e = gh->buckets[bucket_hash]; e; e = e->next) {
- if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
- return e;
- }
+ GHash *gh, const void *key, const unsigned int bucket_index)
+{
+ Entry *e;
+ /* If we do not store GHash, not worth computing it for each entry here!
+ * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
+ for (e = gh->buckets[bucket_index]; e; e = e->next) {
+ if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
+ return e;
}
}
+
return NULL;
}
/**
* Internal lookup function, returns previous entry of target one too.
- * Takes hash and bucket_hash arguments to avoid calling #ghash_keyhash and #ghash_bucket_hash multiple times.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
* Useful when modifying buckets somehow (like removing an entry...).
*/
BLI_INLINE Entry *ghash_lookup_entry_prev_ex(
- GHash *gh, const void *key, Entry **e_prev_r,
- const unsigned int hash, const unsigned int bucket_hash)
-{
- *e_prev_r = NULL;
- if (gh->use_store_hash) {
- if (gh->is_gset) {
- GSetEntryHash *e;
- for (e = (GSetEntryHash *)gh->buckets[bucket_hash]; e; *e_prev_r = (Entry *)e, e = (GSetEntryHash *)e->e.next) {
- if (UNLIKELY(e->hash == hash)) {
- if (LIKELY(gh->cmpfp(key, e->e.key) == false)) {
- return (Entry *)e;
- }
- }
- }
- }
- else {
- GHashEntryHash *e;
- for (e = (GHashEntryHash *)gh->buckets[bucket_hash]; e; *e_prev_r = (Entry *)e, e = (GHashEntryHash *)e->e.next) {
- if (UNLIKELY(e->hash == hash)) {
- if (LIKELY(gh->cmpfp(key, e->e.key) == false)) {
- return (Entry *)e;
- }
- }
- }
- }
- }
- else {
- Entry *e;
- /* If we do not store GHash, not worth computing it for each entry here!
- * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
- for (e = gh->buckets[bucket_hash]; e; *e_prev_r = e, e = e->next) {
- if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
- return e;
- }
+ GHash *gh, const void *key, Entry **r_e_prev, const unsigned int bucket_index)
+{
+ Entry *e, *e_prev = NULL;
+
+ /* If we do not store GHash, not worth computing it for each entry here!
+ * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
+ for (e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
+ if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
+ *r_e_prev = e_prev;
+ return e;
}
}
+
+ *r_e_prev = NULL;
return NULL;
}
@@ -437,13 +406,12 @@ BLI_INLINE Entry *ghash_lookup_entry_prev_ex(
BLI_INLINE Entry *ghash_lookup_entry(GHash *gh, const void *key)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
- return ghash_lookup_entry_ex(gh, key, hash, bucket_hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ return ghash_lookup_entry_ex(gh, key, bucket_index);
}
static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve,
- const bool is_gset, const bool use_store_hash)
+ const unsigned int nentries_reserve, const unsigned int flag)
{
GHash *gh = MEM_mallocN(sizeof(*gh), info);
@@ -451,74 +419,84 @@ static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
gh->cmpfp = cmpfp;
gh->buckets = NULL;
+ gh->flag = flag;
+
ghash_buckets_reset(gh, nentries_reserve);
- gh->entrypool = BLI_mempool_create((unsigned int)GHASH_ENTRY_SIZE(is_gset, use_store_hash), 64, 64, BLI_MEMPOOL_NOP);
- gh->use_store_hash = use_store_hash;
- gh->is_gset = is_gset;
+ gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP);
return gh;
}
/**
* Internal insert function.
- * Takes hash and bucket_hash arguments to avoid calling #ghash_keyhash and #ghash_bucket_hash multiple times.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
*/
BLI_INLINE void ghash_insert_ex(
- GHash *gh, void *key, void *val, const unsigned int hash, const unsigned int bucket_hash)
+ GHash *gh, void *key, void *val, const unsigned int bucket_index)
{
GHashEntry *e = BLI_mempool_alloc(gh->entrypool);
BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
- BLI_assert(!gh->is_gset);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
- e->e.next = gh->buckets[bucket_hash];
+ e->e.next = gh->buckets[bucket_index];
e->e.key = key;
e->val = val;
- if (gh->use_store_hash) {
- ((GHashEntryHash *)e)->hash = hash;
- }
- gh->buckets[bucket_hash] = (Entry *)e;
+ gh->buckets[bucket_index] = (Entry *)e;
+
+ ghash_buckets_expand(gh, ++gh->nentries, false);
+}
- ghash_expand_buckets(gh, ++gh->nentries, false, false);
+/**
+ * Insert function that takes a pre-allocated entry.
+ */
+BLI_INLINE void ghash_insert_ex_keyonly_entry(
+ GHash *gh, void *key, const unsigned int bucket_index,
+ Entry *e)
+{
+ BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
+
+ e->next = gh->buckets[bucket_index];
+ e->key = key;
+ gh->buckets[bucket_index] = e;
+
+ ghash_buckets_expand(gh, ++gh->nentries, false);
}
/**
* Insert function that doesn't set the value (use for GSet)
*/
BLI_INLINE void ghash_insert_ex_keyonly(
- GHash *gh, void *key, const unsigned int hash, const unsigned int bucket_hash)
+ GHash *gh, void *key, const unsigned int bucket_index)
{
- GSetEntry *e = BLI_mempool_alloc(gh->entrypool);
+ Entry *e = BLI_mempool_alloc(gh->entrypool);
BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
- BLI_assert(gh->is_gset);
+ BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
- e->next = gh->buckets[bucket_hash];
+ e->next = gh->buckets[bucket_index];
e->key = key;
- if (gh->use_store_hash) {
- ((GSetEntryHash *)e)->hash = hash;
- }
- gh->buckets[bucket_hash] = (Entry *)e;
+ gh->buckets[bucket_index] = e;
- ghash_expand_buckets(gh, ++gh->nentries, false, false);
+ ghash_buckets_expand(gh, ++gh->nentries, false);
}
BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
- ghash_insert_ex(gh, key, val, hash, bucket_hash);
+ ghash_insert_ex(gh, key, val, bucket_index);
}
BLI_INLINE bool ghash_insert_safe(
GHash *gh, void *key, void *val, const bool override, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
- GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, hash, bucket_hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
- BLI_assert(!gh->is_gset);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
if (e) {
if (override) {
@@ -530,7 +508,7 @@ BLI_INLINE bool ghash_insert_safe(
return false;
}
else {
- ghash_insert_ex(gh, key, val, hash, bucket_hash);
+ ghash_insert_ex(gh, key, val, bucket_index);
return true;
}
}
@@ -538,10 +516,10 @@ BLI_INLINE bool ghash_insert_safe(
BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool override, GHashKeyFreeFP keyfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
- GSetEntry *e = ghash_lookup_entry_ex(gh, key, hash, bucket_hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ Entry *e = ghash_lookup_entry_ex(gh, key, bucket_index);
- BLI_assert(gh->is_gset);
+ BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
if (e) {
if (override) {
@@ -551,7 +529,7 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr
return false;
}
else {
- ghash_insert_ex_keyonly(gh, key, hash, bucket_hash);
+ ghash_insert_ex_keyonly(gh, key, bucket_index);
return true;
}
}
@@ -560,22 +538,22 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr
* Remove the entry and return it, caller must free from gh->entrypool.
*/
static Entry *ghash_remove_ex(
- GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
- const unsigned int hash, const unsigned int bucket_hash)
+ GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
+ const unsigned int bucket_index)
{
Entry *e_prev;
- Entry *e = ghash_lookup_entry_prev_ex(gh, key, &e_prev, hash, bucket_hash);
+ Entry *e = ghash_lookup_entry_prev_ex(gh, key, &e_prev, bucket_index);
- BLI_assert(!valfreefp|| !gh->is_gset);
+ BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
if (e) {
if (keyfreefp) keyfreefp(e->key);
if (valfreefp) valfreefp(((GHashEntry *)e)->val);
if (e_prev) e_prev->next = e->next;
- else gh->buckets[bucket_hash] = e->next;
+ else gh->buckets[bucket_index] = e->next;
- ghash_expand_buckets(gh, --gh->nentries, false, false);
+ ghash_buckets_contract(gh, --gh->nentries, false, false);
}
return e;
@@ -588,8 +566,8 @@ static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP va
{
unsigned int i;
- BLI_assert(keyfreefp || valfreefp);
- BLI_assert(!valfreefp|| !gh->is_gset);
+ BLI_assert(keyfreefp || valfreefp);
+ BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
for (i = 0; i < gh->nbuckets; i++) {
Entry *e;
@@ -608,28 +586,30 @@ static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP val
{
GHash *gh_new;
unsigned int i;
+ /* This allows us to be sure to get the same number of buckets in gh_new as in ghash. */
+ const unsigned int reserve_nentries_new = MAX2(GHASH_LIMIT_GROW(gh->nbuckets) - 1, gh->nentries);
- BLI_assert(!valcopyfp || !gh->is_gset);
+ BLI_assert(!valcopyfp || !(gh->flag & GHASH_FLAG_IS_GSET));
- gh_new = ghash_new(gh->hashfp, gh->cmpfp, __func__, 0, gh->is_gset, gh->use_store_hash);
- ghash_expand_buckets(gh_new, gh->nentries, false, false);
+ gh_new = ghash_new(gh->hashfp, gh->cmpfp, __func__, 0, gh->flag);
+ ghash_buckets_expand(gh_new, reserve_nentries_new, false);
+
+ BLI_assert(gh_new->nbuckets == gh->nbuckets);
for (i = 0; i < gh->nbuckets; i++) {
Entry *e;
for (e = gh->buckets[i]; e; e = e->next) {
Entry *e_new = BLI_mempool_alloc(gh_new->entrypool);
- const unsigned int hash = ghash_entryhash(gh, e);
- const unsigned int gh_new_bucket_hash = ghash_bucket_hash(gh_new, hash);
+ ghash_entry_copy(gh_new, e_new, gh, e, keycopyfp, valcopyfp);
- entry_copy(gh_new, e_new, gh, e, hash, keycopyfp, valcopyfp);
+ /* Warning!
+ * This means entries in buckets in new copy will be in reversed order!
+ * This shall not be an issue though, since order should never be assumed in ghash. */
- /* Warning! This means entries in buckets in new copy will be in reversed order!
- * This shall not be an issue though, since order should never be assumed in ghash. */
- /* Note: We cannot use i here, since there is no guaranty that gh and gh_new
- * have the same number of buckets! */
- e_new->next = gh_new->buckets[gh_new_bucket_hash];
- gh_new->buckets[gh_new_bucket_hash] = e_new;
+ /* Note: We can use 'i' here, since we are sure that 'gh' and 'gh_new' have the same number of buckets! */
+ e_new->next = gh_new->buckets[i];
+ gh_new->buckets[i] = e_new;
}
}
gh_new->nentries = gh->nentries;
@@ -670,23 +650,23 @@ static GHash *ghash_union(
for (e = ghn->buckets[i]; e; e = e->next) {
Entry *e_gh1;
const unsigned int hash = ghash_entryhash(gh1, e);
- const unsigned int gh1_bucket_hash = ghash_bucket_hash(gh1, hash);
+ const unsigned int gh1_bucket_index = ghash_bucket_index(gh1, hash);
- if ((e_gh1 = ghash_lookup_entry_ex(gh1, e->key, hash, gh1_bucket_hash)) == NULL) {
+ if ((e_gh1 = ghash_lookup_entry_ex(gh1, e->key, gh1_bucket_index)) == NULL) {
Entry *e_new = BLI_mempool_alloc(gh1->entrypool);
- entry_copy(gh1, e_new, ghn, e, hash, keycopyfp, valcopyfp);
+ ghash_entry_copy(gh1, e_new, ghn, e, keycopyfp, valcopyfp);
/* As with copy, this does not preserve order (but this would be even less meaningful here). */
- e_new->next = gh1->buckets[gh1_bucket_hash];
- gh1->buckets[gh1_bucket_hash] = e_new;
- ghash_expand_buckets(gh1, ++gh1->nentries, false, false);
+ e_new->next = gh1->buckets[gh1_bucket_index];
+ gh1->buckets[gh1_bucket_index] = e_new;
+ ghash_buckets_expand(gh1, ++gh1->nentries, false);
}
else if (reverse) {
if (keyfreefp) keyfreefp(e_gh1->key);
if (valfreefp) valfreefp(((GHashEntry *)e_gh1)->val);
- entry_copy(gh1, e_gh1, ghn, e, hash, keycopyfp, valcopyfp);
+ ghash_entry_copy(gh1, e_gh1, ghn, e, keycopyfp, valcopyfp);
}
}
}
@@ -727,11 +707,11 @@ static GHash *ghash_intersection(
for (e = gh1->buckets[i]; e; e = e_next) {
const unsigned int hash = ghash_entryhash(gh1, e);
- const unsigned int ghn_bucket_hash = ghash_bucket_hash(ghn, hash);
+ const unsigned int ghn_bucket_index = ghash_bucket_index(ghn, hash);
e_next = e->next;
- if (ghash_lookup_entry_ex(ghn, e->key, hash, ghn_bucket_hash) == NULL) {
+ if (ghash_lookup_entry_ex(ghn, e->key, ghn_bucket_index) == NULL) {
if (keyfreefp) keyfreefp(e->key);
if (valfreefp) valfreefp(((GHashEntry *)e)->val);
@@ -750,7 +730,7 @@ static GHash *ghash_intersection(
gh1->nentries = new_gh1_nentries;
/* We force shrinking here (if needed). */
- ghash_expand_buckets(gh1, gh1->nentries, false, true);
+ ghash_buckets_contract(gh1, gh1->nentries, false, true);
}
return gh1;
@@ -788,11 +768,11 @@ static GHash *ghash_difference(
for (e = gh1->buckets[i]; e; e = e_next) {
const unsigned int hash = ghash_entryhash(gh1, e);
- const unsigned int ghn_bucket_hash = ghash_bucket_hash(ghn, hash);
+ const unsigned int ghn_bucket_index = ghash_bucket_index(ghn, hash);
e_next = e->next;
- if (ghash_lookup_entry_ex(ghn, e->key, hash, ghn_bucket_hash) != NULL) {
+ if (ghash_lookup_entry_ex(ghn, e->key, ghn_bucket_index) != NULL) {
if (keyfreefp) keyfreefp(e->key);
if (valfreefp) valfreefp(((GHashEntry *)e)->val);
@@ -811,7 +791,7 @@ static GHash *ghash_difference(
gh1->nentries = new_gh1_nentries;
/* We force shrinking here (if needed). */
- ghash_expand_buckets(gh1, gh1->nentries, false, true);
+ ghash_buckets_contract(gh1, gh1->nentries, false, true);
}
return gh1;
@@ -843,41 +823,41 @@ static GHash *ghash_symmetric_difference(
BLI_assert(!valfreefp || !gh1->is_gset);
keys = ghash_copy(gh1, NULL, NULL);
- rem_keys = ghash_new(gh1->hashfp, gh1->cmpfp, __func__, 64, true, gh1->use_store_hash);
+ rem_keys = ghash_new(gh1->hashfp, gh1->cmpfp, __func__, 64, true);
/* First pass: all key found at least once is in keys, all key found at least twice is in rem_keys. */
for ( ; ghn; ghn = va_arg(arg, GHash *)) {
BLI_assert(gh1->cmpfp == ghn->cmpfp);
BLI_assert(gh1->hashfp == ghn->hashfp);
- BLI_assert(gh1->is_gset == ghn->is_gset);
+ BLI_assert((gh1->flag & GHASH_FLAG_IS_GSET) == (ghn->is_gset & GHASH_FLAG_IS_GSET));
for (i = 0; i < ghn->nbuckets; i++) {
Entry *e;
for (e = ghn->buckets[i]; e; e = e->next) {
const unsigned int hash = ghash_entryhash(ghn, e);
- const unsigned int keys_bucket_hash = ghash_bucket_hash(keys, hash);
+ const unsigned int keys_bucket_index = ghash_bucket_index(keys, hash);
- if (ghash_lookup_entry_ex(keys, e->key, hash, keys_bucket_hash) != NULL) {
- const unsigned int rem_keys_bucket_hash = ghash_bucket_hash(rem_keys, hash);
+ if (ghash_lookup_entry_ex(keys, e->key, keys_bucket_index) != NULL) {
+ const unsigned int rem_keys_bucket_index = ghash_bucket_index(rem_keys, hash);
Entry *e_new = BLI_mempool_alloc(rem_keys->entrypool);
- entry_copy(rem_keys, e_new, ghn, e, hash, NULL, NULL);
+ ghash_entry_copy(rem_keys, e_new, ghn, e, NULL, NULL);
/* As with copy, this does not preserve order (but this would be even less meaningful here). */
- e_new->next = rem_keys->buckets[rem_keys_bucket_hash];
- rem_keys->buckets[rem_keys_bucket_hash] = e_new;
- ghash_expand_buckets(rem_keys, ++rem_keys->nentries, false, false);
+ e_new->next = rem_keys->buckets[rem_keys_bucket_index];
+ rem_keys->buckets[rem_keys_bucket_index] = e_new;
+ ghash_buckets_expand(rem_keys, ++rem_keys->nentries, false);
}
else {
Entry *e_new = BLI_mempool_alloc(keys->entrypool);
- entry_copy(keys, e_new, ghn, e, hash, NULL, NULL);
+ ghash_entry_copy(keys, e_new, ghn, e, NULL, NULL);
/* As with copy, this does not preserve order (but this would be even less meaningful here). */
- e_new->next = keys->buckets[keys_bucket_hash];
- keys->buckets[keys_bucket_hash] = e_new;
- ghash_expand_buckets(keys, ++keys->nentries, false, false);
+ e_new->next = keys->buckets[keys_bucket_index];
+ keys->buckets[keys_bucket_index] = e_new;
+ ghash_buckets_expand(keys, ++keys->nentries, false);
}
}
}
@@ -890,24 +870,24 @@ static GHash *ghash_symmetric_difference(
for (e = rem_keys->buckets[i]; e; e = e->next) {
Entry *e_prev, *e_curr;
const unsigned int hash = ghash_entryhash(rem_keys, e);
- const unsigned int keys_bucket_hash = ghash_bucket_hash(keys, hash);
- const unsigned int gh1_bucket_hash = ghash_bucket_hash(gh1, hash);
+ const unsigned int keys_bucket_index = ghash_bucket_index(keys, hash);
+ const unsigned int gh1_bucket_index = ghash_bucket_index(gh1, hash);
- e_curr = ghash_lookup_entry_prev_ex(keys, e->key, &e_prev, hash, keys_bucket_hash);
+ e_curr = ghash_lookup_entry_prev_ex(keys, e->key, &e_prev, keys_bucket_index);
BLI_assert(e_curr != NULL); /* All keys in rem_keys must exist in keys! */
if (e_prev) e_prev->next = e_curr->next;
- else keys->buckets[keys_bucket_hash] = e_curr->next;
+ else keys->buckets[keys_bucket_index] = e_curr->next;
/* We do not care about shrinking keys' buckets here! */
keys->nentries--;
BLI_mempool_free(keys->entrypool, e_curr);
/* Also remove keys from gh1 if possible, since we are at it... */
- e_curr = ghash_lookup_entry_prev_ex(gh1, e->key, &e_prev, hash, gh1_bucket_hash);
+ e_curr = ghash_lookup_entry_prev_ex(gh1, e->key, &e_prev, gh1_bucket_index);
if (e_curr) {
if (e_prev) e_prev->next = e_curr->next;
- else gh1->buckets[gh1_bucket_hash] = e_curr->next;
+ else gh1->buckets[gh1_bucket_index] = e_curr->next;
/* Note: We can free key/value here, because we won't use them again (have been removed
* from keys already, and we won't use matching entry from rem_key again either. */
@@ -929,17 +909,17 @@ static GHash *ghash_symmetric_difference(
for (e = keys->buckets[i]; e; e = e->next) {
const unsigned int hash = ghash_entryhash(keys, e);
- const unsigned int gh1_bucket_hash = ghash_bucket_hash(gh1, hash);
+ const unsigned int gh1_bucket_index = ghash_bucket_index(gh1, hash);
- if (ghash_lookup_entry_ex(gh1, e->key, hash, gh1_bucket_hash) == NULL) {
+ if (ghash_lookup_entry_ex(gh1, e->key, gh1_bucket_index) == NULL) {
Entry *e_new = BLI_mempool_alloc(gh1->entrypool);
- entry_copy(gh1, e_new, keys, e, hash, keycopyfp, valcopyfp);
+ ghash_entry_copy(gh1, e_new, keys, e, keycopyfp, valcopyfp);
/* As with copy, this does not preserve order (but this would be even less meaningful here). */
- e_new->next = gh1->buckets[gh1_bucket_hash];
- gh1->buckets[gh1_bucket_hash] = e_new;
- ghash_expand_buckets(gh1, ++gh1->nentries, false, false);
+ e_new->next = gh1->buckets[gh1_bucket_index];
+ gh1->buckets[gh1_bucket_index] = e_new;
+ ghash_buckets_expand(gh1, ++gh1->nentries, false);
}
}
}
@@ -947,7 +927,7 @@ static GHash *ghash_symmetric_difference(
BLI_ghash_free(keys, NULL, NULL);
/* We force shrinking here (if needed). */
- ghash_expand_buckets(gh1, gh1->nentries, false, true);
+ ghash_buckets_contract(gh1, gh1->nentries, false, true);
return gh1;
}
@@ -969,10 +949,9 @@ static GHash *ghash_symmetric_difference(
* \return An empty GHash.
*/
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve, const bool store_hash)
+ const unsigned int nentries_reserve)
{
- UNUSED_VARS(store_hash);
- return ghash_new(hashfp, cmpfp, info, nentries_reserve, false, GHASH_STORE_HASH);
+ return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
/**
@@ -980,7 +959,7 @@ GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
*/
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
{
- return BLI_ghash_new_ex(hashfp, cmpfp, info, 0, false);
+ return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
}
/**
@@ -996,15 +975,16 @@ GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcop
*/
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve)
{
- ghash_expand_buckets(gh, nentries_reserve, true, false);
+ ghash_buckets_expand(gh, nentries_reserve, true);
+ ghash_buckets_contract(gh, nentries_reserve, true, false);
}
/**
* \return size of the GHash.
*/
-int BLI_ghash_size(GHash *gh)
+unsigned int BLI_ghash_size(GHash *gh)
{
- return (int)gh->nentries;
+ return gh->nentries;
}
/**
@@ -1020,18 +1000,6 @@ void BLI_ghash_insert(GHash *gh, void *key, void *val)
}
/**
- * Like #BLI_ghash_insert, but does nothing in case \a key is already in the \a gh.
- *
- * Avoids #BLI_ghash_haskey, #BLI_ghash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
-bool BLI_ghash_add(GHash *gh, void *key, void *val)
-{
- return ghash_insert_safe(gh, key, val, false, NULL, NULL);
-}
-
-/**
* Inserts a new value to a key that may already be in ghash.
*
* Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
@@ -1055,7 +1023,7 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreef
void *BLI_ghash_lookup(GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
- BLI_assert(!gh->is_gset);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? e->val : NULL;
}
@@ -1065,7 +1033,7 @@ void *BLI_ghash_lookup(GHash *gh, const void *key)
void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
- BLI_assert(!gh->is_gset);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? e->val : val_default;
}
@@ -1082,11 +1050,63 @@ void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default)
void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
- BLI_assert(!gh->is_gset);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? &e->val : NULL;
}
/**
+ * Ensure \a key is exists in \a gh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a gh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
+bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
+{
+ 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);
+ const bool haskey = (e != NULL);
+
+ if (!haskey) {
+ e = BLI_mempool_alloc(gh->entrypool);
+ ghash_insert_ex_keyonly_entry(gh, key, bucket_index, (Entry *)e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
+ * A version of #BLI_ghash_ensure_p copies the key on insertion.
+ */
+bool BLI_ghash_ensure_p_ex(
+ GHash *gh, const void *key, void ***r_val,
+ GHashKeyCopyFP keycopyfp)
+{
+ 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);
+ const bool haskey = (e != NULL);
+
+ if (!haskey) {
+ /* keycopyfp(key) is the only difference to BLI_ghash_ensure_p */
+ e = BLI_mempool_alloc(gh->entrypool);
+ ghash_insert_ex_keyonly_entry(gh, keycopyfp(key), bucket_index, (Entry *)e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
* Remove \a key from \a gh, or return false if the key wasn't found.
*
* \param key The key to remove.
@@ -1094,11 +1114,11 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
* \param valfreefp Optional callback to free the value.
* \return true if \a key was removed from \a gh.
*/
-bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
- Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, hash, bucket_hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, bucket_index);
if (e) {
BLI_mempool_free(gh->entrypool, e);
return true;
@@ -1117,12 +1137,12 @@ bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFr
* \param keyfreefp Optional callback to free the key.
* \return the value of \a key int \a gh or NULL.
*/
-void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp)
+void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- const unsigned int bucket_hash = ghash_bucket_hash(gh, hash);
- GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, hash, bucket_hash);
- BLI_assert(!gh->is_gset);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
if (e) {
void *val = e->val;
BLI_mempool_free(gh->entrypool, e);
@@ -1189,7 +1209,7 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
*/
void BLI_ghash_flag_set(GHash *gh, unsigned int flag)
{
- gh->flag |= (unsigned short)flag;
+ gh->flag |= flag;
}
/**
@@ -1197,7 +1217,7 @@ void BLI_ghash_flag_set(GHash *gh, unsigned int flag)
*/
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag)
{
- gh->flag &= (unsigned short)~flag;
+ gh->flag &= ~flag;
}
/**
@@ -1212,8 +1232,7 @@ bool BLI_ghash_isdisjoint(GHash *gh1, GHash *gh2)
BLI_assert(gh1->cmpfp == gh2->cmpfp);
BLI_assert(gh1->hashfp == gh2->hashfp);
- if (((gh1->nentries > gh2->nentries) && (gh2->use_store_hash || !gh1->use_store_hash)) ||
- (gh2->use_store_hash && !gh1->use_store_hash))
+ if (gh1->nentries > gh2->nentries)
{
SWAP(GHash *, gh1, gh2);
}
@@ -1223,8 +1242,8 @@ bool BLI_ghash_isdisjoint(GHash *gh1, GHash *gh2)
for (e = gh1->buckets[i]; e; e = e->next) {
const unsigned int hash = ghash_entryhash(gh1, e);
- const unsigned int gh2_bucket_hash = ghash_bucket_hash(gh2, hash);
- if (ghash_lookup_entry_ex(gh2, e->key, hash, gh2_bucket_hash)) {
+ const unsigned int gh2_bucket_index = ghash_bucket_index(gh2, hash);
+ if (ghash_lookup_entry_ex(gh2, e->key, gh2_bucket_index)) {
return false;
}
}
@@ -1247,17 +1266,13 @@ bool BLI_ghash_isequal(GHash *gh1, GHash *gh2)
return false;
}
- if (gh2->use_store_hash && !gh1->use_store_hash) {
- SWAP(GHash *, gh1, gh2);
- }
-
for (i = 0; i < gh1->nbuckets; i++) {
Entry *e;
for (e = gh1->buckets[i]; e; e = e->next) {
const unsigned int hash = ghash_entryhash(gh1, e);
- unsigned int gh2_bucket_hash = ghash_bucket_hash(gh2, hash);
- if (!ghash_lookup_entry_ex(gh2, e->key, hash, gh2_bucket_hash)) {
+ unsigned int gh2_bucket_index = ghash_bucket_index(gh2, hash);
+ if (!ghash_lookup_entry_ex(gh2, e->key, gh2_bucket_index)) {
return false;
}
}
@@ -1288,8 +1303,8 @@ bool BLI_ghash_issubset(GHash *gh1, GHash *gh2)
for (e = gh2->buckets[i]; e; e = e->next) {
const unsigned int hash = ghash_entryhash(gh2, e);
- const unsigned int gh1_bucket_hash = ghash_bucket_hash(gh1, hash);
- if (!ghash_lookup_entry_ex(gh1, e->key, hash, gh1_bucket_hash)) {
+ const unsigned int gh1_bucket_index = ghash_bucket_index(gh1, hash);
+ if (!ghash_lookup_entry_ex(gh1, e->key, gh1_bucket_index)) {
return false;
}
}
@@ -1594,7 +1609,7 @@ unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4])
}
unsigned int BLI_ghashutil_uinthash_v4_murmur(const unsigned int key[4])
{
- return BLI_hash_mm2((const unsigned char *)key, sizeof(key), 0);
+ return BLI_hash_mm2((const unsigned char *)key, sizeof(int) * 4 /* sizeof(key) */, 0);
}
bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b)
@@ -1635,6 +1650,11 @@ unsigned int BLI_ghashutil_inthash_p_murmur(const void *ptr)
return BLI_hash_mm2((const unsigned char *)&key, sizeof(key), 0);
}
+unsigned int BLI_ghashutil_inthash_p_simple(const void *ptr)
+{
+ return GET_UINT_FROM_POINTER(ptr);
+}
+
bool BLI_ghashutil_intcmp(const void *a, const void *b)
{
return (a != b);
@@ -1719,7 +1739,7 @@ void BLI_ghashutil_pairfree(void *ptr)
GHash *BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve, false);
+ return BLI_ghash_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve);
}
GHash *BLI_ghash_ptr_new(const char *info)
{
@@ -1728,7 +1748,7 @@ GHash *BLI_ghash_ptr_new(const char *info)
GHash *BLI_ghash_str_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, info, nentries_reserve, true);
+ return BLI_ghash_new_ex(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, info, nentries_reserve);
}
GHash *BLI_ghash_str_new(const char *info)
{
@@ -1737,7 +1757,7 @@ GHash *BLI_ghash_str_new(const char *info)
GHash *BLI_ghash_int_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info, nentries_reserve, false);
+ return BLI_ghash_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info, nentries_reserve);
}
GHash *BLI_ghash_int_new(const char *info)
{
@@ -1746,7 +1766,7 @@ GHash *BLI_ghash_int_new(const char *info)
GHash *BLI_ghash_pair_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve, false);
+ return BLI_ghash_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve);
}
GHash *BLI_ghash_pair_new(const char *info)
{
@@ -1764,15 +1784,14 @@ GHash *BLI_ghash_pair_new(const char *info)
/** \name GSet Functions
* \{ */
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve, const bool store_hash)
+ const unsigned int nentries_reserve)
{
- UNUSED_VARS(store_hash);
- return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, true, GHASH_STORE_HASH);
+ return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, GHASH_FLAG_IS_GSET);
}
GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
{
- return BLI_gset_new_ex(hashfp, cmpfp, info, 0, false);
+ return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
}
/**
@@ -1783,9 +1802,9 @@ GSet *BLI_gset_copy(GSet *gs, GHashKeyCopyFP keycopyfp)
return (GSet *)ghash_copy((GHash *)gs, keycopyfp, NULL);
}
-int BLI_gset_size(GSet *gs)
+unsigned int BLI_gset_size(GSet *gs)
{
- return (int)((GHash *)gs)->nentries;
+ return ((GHash *)gs)->nentries;
}
/**
@@ -1795,8 +1814,8 @@ int BLI_gset_size(GSet *gs)
void BLI_gset_insert(GSet *gs, void *key)
{
const unsigned int hash = ghash_keyhash((GHash *)gs, key);
- const unsigned int bucket_hash = ghash_bucket_hash((GHash *)gs, hash);
- ghash_insert_ex_keyonly((GHash *)gs, key, hash, bucket_hash);
+ const unsigned int bucket_index = ghash_bucket_index((GHash *)gs, hash);
+ ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
}
/**
@@ -1821,7 +1840,7 @@ bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
-bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
+bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
{
return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL);
}
@@ -1851,12 +1870,12 @@ void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
void BLI_gset_flag_set(GSet *gs, unsigned int flag)
{
- ((GHash *)gs)->flag |= (unsigned short)flag;
+ ((GHash *)gs)->flag |= flag;
}
void BLI_gset_flag_clear(GSet *gs, unsigned int flag)
{
- ((GHash *)gs)->flag &= (unsigned short)~flag;
+ ((GHash *)gs)->flag &= ~flag;
}
bool BLI_gset_isdisjoint(GSet *gs1, GSet *gs2)
@@ -1952,7 +1971,7 @@ GSet *BLI_gset_symmetric_difference(GSetKeyCopyFP keycopyfp, GSetKeyFreeFP keyfr
GSet *BLI_gset_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve, false);
+ return BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve);
}
GSet *BLI_gset_ptr_new(const char *info)
{
@@ -1961,7 +1980,7 @@ GSet *BLI_gset_ptr_new(const char *info)
GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_gset_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve, false);
+ return BLI_gset_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve);
}
GSet *BLI_gset_pair_new(const char *info)
{
@@ -1994,7 +2013,7 @@ int BLI_gset_buckets_size(GSet *gs)
*
* Smaller is better!
*/
-double BLI_ghash_calc_quality(
+double BLI_ghash_calc_quality_ex(
GHash *gh, double *r_load, double *r_variance,
double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
{
@@ -2046,41 +2065,53 @@ double BLI_ghash_calc_quality(
}
{
- uint64_t sum = 0;
- uint64_t overloaded_buckets_threshold = (uint64_t)max_ii(GHASH_LIMIT_GROW(1), 1);
- uint64_t sum_overloaded = 0;
- uint64_t sum_empty = 0;
-
- for (i = 0; i < gh->nbuckets; i++) {
- uint64_t count = 0;
- Entry *e;
- for (e = gh->buckets[i]; e; e = e->next) {
- count++;
- }
- if (r_biggest_bucket) {
- *r_biggest_bucket = max_ii(*r_biggest_bucket, (int)count);
- }
- if (r_prop_overloaded_buckets && (count > overloaded_buckets_threshold)) {
- sum_overloaded++;
- }
- if (r_prop_empty_buckets && !count) {
- sum_empty++;
- }
- sum += count * (count + 1);
- }
- if (r_prop_overloaded_buckets) {
- *r_prop_overloaded_buckets = (double)sum_overloaded / (double)gh->nbuckets;
- }
- if (r_prop_empty_buckets) {
- *r_prop_empty_buckets = (double)sum_empty / (double)gh->nbuckets;
- }
- return ((double)sum * (double)gh->nbuckets /
- ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
- }
-}
-double BLI_gset_calc_quality(GSet *gs, double *r_load, double *r_variance, double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
-{
- return BLI_ghash_calc_quality((GHash *)gs, r_load, r_variance, r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket);
+ uint64_t sum = 0;
+ uint64_t overloaded_buckets_threshold = (uint64_t)max_ii(GHASH_LIMIT_GROW(1), 1);
+ uint64_t sum_overloaded = 0;
+ uint64_t sum_empty = 0;
+
+ for (i = 0; i < gh->nbuckets; i++) {
+ uint64_t count = 0;
+ Entry *e;
+ for (e = gh->buckets[i]; e; e = e->next) {
+ count++;
+ }
+ if (r_biggest_bucket) {
+ *r_biggest_bucket = max_ii(*r_biggest_bucket, (int)count);
+ }
+ if (r_prop_overloaded_buckets && (count > overloaded_buckets_threshold)) {
+ sum_overloaded++;
+ }
+ if (r_prop_empty_buckets && !count) {
+ sum_empty++;
+ }
+ sum += count * (count + 1);
+ }
+ if (r_prop_overloaded_buckets) {
+ *r_prop_overloaded_buckets = (double)sum_overloaded / (double)gh->nbuckets;
+ }
+ if (r_prop_empty_buckets) {
+ *r_prop_empty_buckets = (double)sum_empty / (double)gh->nbuckets;
+ }
+ return ((double)sum * (double)gh->nbuckets /
+ ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
+ }
+}
+double BLI_gset_calc_quality_ex(
+ GSet *gs, double *r_load, double *r_variance,
+ double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
+{
+ return BLI_ghash_calc_quality_ex((GHash *)gs, r_load, r_variance,
+ r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket);
+}
+
+double BLI_ghash_calc_quality(GHash *gh)
+{
+ return BLI_ghash_calc_quality_ex(gh, NULL, NULL, NULL, NULL, NULL);
+}
+double BLI_gset_calc_quality(GSet *gs)
+{
+ return BLI_ghash_calc_quality_ex((GHash *)gs, NULL, NULL, NULL, NULL, NULL);
}
/** \} */
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 66dfa87b7b9..c0f338a1918 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -183,8 +183,8 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node));
}
- node->value = value;
node->ptr = ptr;
+ node->value = value;
node->index = heap->size;
heap->tree[node->index] = node;
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 391f3ef7702..1da39967945 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -30,6 +30,7 @@
* \ingroup bli
*/
+#include <stdlib.h>
#include "MEM_guardedalloc.h"
@@ -38,7 +39,9 @@
#include "BLI_memarena.h"
#include "BLI_mempool.h"
-int BLI_linklist_length(LinkNode *list)
+#include "BLI_strict_flags.h"
+
+int BLI_linklist_count(LinkNode *list)
{
int len;
@@ -188,40 +191,39 @@ void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool
/**
* A version of append that takes the allocated link.
*/
-void BLI_linklist_append_nlink(LinkNode **listp, void *ptr, LinkNode *nlink)
+void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
{
- LinkNode *node = *listp;
-
nlink->link = ptr;
nlink->next = NULL;
- if (node == NULL) {
- *listp = nlink;
+ if (list_pair->list) {
+ BLI_assert((list_pair->last_node != NULL) && (list_pair->last_node->next == NULL));
+ list_pair->last_node->next = nlink;
}
else {
- while (node->next != NULL) {
- node = node->next;
- }
- node->next = nlink;
+ BLI_assert(list_pair->last_node == NULL);
+ list_pair->list = nlink;
}
+
+ list_pair->last_node = nlink;
}
-void BLI_linklist_append(LinkNode **listp, void *ptr)
+void BLI_linklist_append(LinkNodePair *list_pair, void *ptr)
{
LinkNode *nlink = MEM_mallocN(sizeof(*nlink), __func__);
- BLI_linklist_append_nlink(listp, ptr, nlink);
+ BLI_linklist_append_nlink(list_pair, ptr, nlink);
}
-void BLI_linklist_append_arena(LinkNode **listp, void *ptr, MemArena *ma)
+void BLI_linklist_append_arena(LinkNodePair *list_pair, void *ptr, MemArena *ma)
{
LinkNode *nlink = BLI_memarena_alloc(ma, sizeof(*nlink));
- BLI_linklist_append_nlink(listp, ptr, nlink);
+ BLI_linklist_append_nlink(list_pair, ptr, nlink);
}
-void BLI_linklist_append_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool)
+void BLI_linklist_append_pool(LinkNodePair *list_pair, void *ptr, BLI_mempool *mempool)
{
LinkNode *nlink = BLI_mempool_alloc(mempool);
- BLI_linklist_append_nlink(listp, ptr, nlink);
+ BLI_linklist_append_nlink(list_pair, ptr, nlink);
}
void *BLI_linklist_pop(struct LinkNode **listp)
@@ -230,7 +232,7 @@ void *BLI_linklist_pop(struct LinkNode **listp)
void *link = (*listp)->link;
void *next = (*listp)->next;
- MEM_freeN((*listp));
+ MEM_freeN(*listp);
*listp = next;
return link;
@@ -308,3 +310,40 @@ void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdat
for (; list; list = list->next)
applyfunc(list->link, userdata);
}
+
+/* -------------------------------------------------------------------- */
+/* Sort */
+#define SORT_IMPL_LINKTYPE LinkNode
+#define SORT_IMPL_LINKTYPE_DATA link
+
+/* regular call */
+#define SORT_IMPL_FUNC linklist_sort_fn
+#include "list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+
+/* reentrant call */
+#define SORT_IMPL_USE_THUNK
+#define SORT_IMPL_FUNC linklist_sort_fn_r
+#include "list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+#undef SORT_IMPL_USE_THUNK
+
+#undef SORT_IMPL_LINKTYPE
+#undef SORT_IMPL_LINKTYPE_DATA
+
+
+LinkNode *BLI_linklist_sort(LinkNode *list, int (*cmp)(const void *, const void *))
+{
+ if (list && list->next) {
+ list = linklist_sort_fn(list, cmp);
+ }
+ return list;
+}
+
+LinkNode *BLI_linklist_sort_r(LinkNode *list, int (*cmp)(void *, const void *, const void *), void *thunk)
+{
+ if (list && list->next) {
+ list = linklist_sort_fn_r(list, cmp, thunk);
+ }
+ return list;
+}
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 173effbc434..6c5dc5a7f1e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -25,23 +25,28 @@
#include <string.h>
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_array_utils.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
+#include "BLI_strict_flags.h"
+
void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
{
- const unsigned int arr_half_stride = (arr_len / 2) * arr_stride;
+ const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const unsigned int arr_half_stride = (arr_len / 2) * arr_stride_uint;
unsigned int i, i_end;
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
- for (i = 0, i_end = (arr_len - 1) * arr_stride;
+ for (i = 0, i_end = (arr_len - 1) * arr_stride_uint;
i < arr_half_stride;
- i += arr_stride, i_end -= arr_stride)
+ i += arr_stride_uint, i_end -= arr_stride_uint)
{
memcpy(buf, &arr[i], arr_stride);
memcpy(&arr[i], &arr[i_end], arr_stride);
@@ -69,6 +74,36 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d
}
}
+void _bli_array_permute(
+ void *arr_v, const unsigned int arr_len, const size_t arr_stride,
+ const unsigned int *order, void *arr_temp)
+{
+ const size_t len = arr_len * arr_stride;
+ const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ void *arr_orig;
+ unsigned int i;
+
+ if (arr_temp == NULL) {
+ arr_orig = MEM_mallocN(len, __func__);
+ }
+ else {
+ arr_orig = arr_temp;
+ }
+
+ memcpy(arr_orig, arr_v, len);
+
+ for (i = 0; i < arr_len; i++) {
+ BLI_assert(order[i] < arr_len);
+ memcpy(POINTER_OFFSET(arr_v, arr_stride_uint * i),
+ POINTER_OFFSET(arr_orig, arr_stride_uint * order[i]),
+ arr_stride);
+ }
+
+ if (arr_temp == NULL) {
+ MEM_freeN(arr_orig);
+ }
+}
+
/**
* \note Not efficient, use for error checks/asserts.
*/
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index b7b41d2497e..21d974de1c4 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -165,18 +165,6 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
}
/**
- * Callback computing the current cost (distance) to next node, and the estimated overall cost to destination node
- * (A* expects this estimation to always be less or equal than actual shortest path from next node to destination one).
- *
- * \param link the graph link between current node and next one.
- * \param node_idx_curr current node index.
- * \param node_idx_next next node index.
- * \param node_idx_dst destination node index.
- */
-typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link,
- const int node_idx_curr, const int node_idx_next, const int node_idx_dst);
-
-/**
* Init an A* graph. Total number of nodes must be known.
*
* Nodes might be e.g. vertices, faces, ...
@@ -229,7 +217,7 @@ bool BLI_astar_graph_solve(
r_solution->steps = 0;
prev_nodes[node_index_src] = -1;
BLI_BITMAP_SET_ALL(done_nodes, false, as_graph->node_num);
- fill_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
+ copy_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
g_costs[node_index_src] = 0.0f;
g_steps[node_index_src] = 0;
diff --git a/source/blender/blenlib/intern/convexhull2d.c b/source/blender/blenlib/intern/convexhull2d.c
index 5f64088f433..740f3cce4a4 100644
--- a/source/blender/blenlib/intern/convexhull2d.c
+++ b/source/blender/blenlib/intern/convexhull2d.c
@@ -239,7 +239,7 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
*
* Intended to be used with #BLI_convexhull_2d
*
- * \param points Orded hull points
+ * \param points_hull Ordered hull points
* (result of #BLI_convexhull_2d mapped to a contiguous array).
*
* \note we could return the index of the best edge too if its needed.
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 82d57dad753..cde4a8bf59d 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -240,6 +240,30 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign
e->next = eh->buckets[hash];
e->v0 = v0;
e->v1 = v1;
+ eh->buckets[hash] = e;
+
+ if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
+ edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
+ }
+}
+
+/**
+ * Insert function that doesn't set the value (use for EdgeSet)
+ */
+BLI_INLINE void edgehash_insert_ex_keyonly_entry(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ unsigned int hash,
+ EdgeEntry *e)
+{
+ BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0));
+
+ /* this helps to track down errors with bad edge data */
+ BLI_assert(v0 < v1);
+ BLI_assert(v0 != v1);
+
+ e->next = eh->buckets[hash];
+ e->v0 = v0;
+ e->v1 = v1;
/* intentionally leave value unset */
eh->buckets[hash] = e;
@@ -373,6 +397,40 @@ void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1)
}
/**
+ * Ensure \a (v0, v1) is exists in \a eh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a eh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
+bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
+{
+ unsigned int hash;
+ EdgeEntry *e;
+ bool haskey;
+
+ EDGE_ORD(v0, v1); /* ensure v0 is smaller */
+ hash = edgehash_keyhash(eh, v0, v1);
+ e = edgehash_lookup_entry_ex(eh, v0, v1, hash);
+ haskey = (e != NULL);
+
+ if (!haskey) {
+ e = BLI_mempool_alloc(eh->epool);
+ edgehash_insert_ex_keyonly_entry(eh, v0, v1, hash, e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
* Return value for given edge (\a v0, \a v1), or NULL if
* if key does not exist in hash. (If need exists
* to differentiate between key-value being NULL and
@@ -396,9 +454,9 @@ void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1
}
/**
- * Remove \a key from \a eh, or return false if the key wasn't found.
+ * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
*
- * \param key The key to remove.
+ * \param v0, v1: The key to remove.
* \param valfreefp Optional callback to free the value.
* \return true if \a key was removed from \a eh.
*/
@@ -422,9 +480,9 @@ bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHas
/* same as above but return the value,
* no free value argument since it will be returned */
/**
- * Remove \a key from \a eh, returning the value or NULL if the key wasn't found.
+ * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
*
- * \param key The key to remove.
+ * \param v0, v1: The key to remove.
* \return the value of \a key int \a eh or NULL.
*/
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1)
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index d6fe5e52b95..c3e889842c1 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -657,21 +657,29 @@ static int delete_single_file(const char *from, const char *UNUSED(to))
FILE *BLI_fopen(const char *filename, const char *mode)
{
+ BLI_assert(!BLI_path_is_rel(filename));
+
return fopen(filename, mode);
}
void *BLI_gzopen(const char *filename, const char *mode)
{
+ BLI_assert(!BLI_path_is_rel(filename));
+
return gzopen(filename, mode);
}
int BLI_open(const char *filename, int oflag, int pmode)
{
+ BLI_assert(!BLI_path_is_rel(filename));
+
return open(filename, oflag, pmode);
}
int BLI_access(const char *filename, int mode)
{
+ BLI_assert(!BLI_path_is_rel(filename));
+
return access(filename, mode);
}
@@ -682,6 +690,8 @@ int BLI_access(const char *filename, int mode)
*/
int BLI_delete(const char *file, bool dir, bool recursive)
{
+ BLI_assert(!BLI_path_is_rel(file));
+
if (recursive) {
return recursive_operation(file, NULL, NULL, delete_single_file, delete_callback_post);
}
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index b3392e28223..8719c92a2a6 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -507,8 +507,7 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
/* Freetype2 Outline struct */
-typedef struct FT_Outline_
-{
+typedef struct FT_Outline_ {
short n_contours; /* number of contours in glyph */
short n_points; /* number of points in the glyph */
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 94d18ce3c77..f1aff76b358 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -96,8 +96,8 @@ int BLI_gsqueue_size(GSQueue *gq)
* Access the item at the head of the queue
* without removing it.
*
- * \param item_r A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new)
+ * \param r_item: A pointer to an appropriately
+ * sized structure (the size passed to #BLI_gsqueue_new)
*/
void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
{
@@ -108,8 +108,8 @@ void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
* Access the item at the head of the queue
* and remove it.
*
- * \param item_r A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * \param r_item: A pointer to an appropriately
+ * sized structure (the size passed to #BLI_gsqueue_new).
* Can be NULL if desired.
*/
void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 4eec38278e9..d98b915983c 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -81,8 +81,7 @@
* 'BLI_hash_md5_stream' and 'BLI_hash_md5_buffer'. */
/* Structure to save state of computation between the single steps. */
-struct md5_ctx
-{
+struct md5_ctx {
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index 30bd59b05b9..af6ef4f355f 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -135,11 +135,11 @@ uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
case 1:
h ^= data[0];
h *= MM2A_M;
- };
+ }
/* Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. */
MM2A_MIX_FINALIZE(h);
return h;
-}
+}
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
new file mode 100644
index 00000000000..249ed470d6e
--- /dev/null
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -0,0 +1,341 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/list_sort_impl.h
+ * \ingroup bli
+ *
+ * Common implementation of linked-list a non-recursive mergesort.
+ *
+ * Originally from Mono's eglib, adapted for portable inclusion.
+ * This file is to be directly included in C-source,
+ * with defines to control its use.
+ *
+ * This code requires a typedef named `SORT_IMPL_LINKTYPE` for the list node.
+ * It is assumed that the list type is the type of a pointer to a list
+ * node, and that the node has a field named 'next' that implements to
+ * the linked list. No additional invariant is maintained
+ * (e.g. the `prev` pointer of a doubly-linked list node is _not_ updated).
+ * Any invariant would require a post-processing pass to update `prev`.
+ *
+ * Source file including this must define:
+ * - `SORT_IMPL_LINKTYPE`:
+ * Struct type for sorting.
+ * - `SORT_IMPL_LINKTYPE_DATA`:
+ * Data pointer or leave undefined to pass the link its self.
+ * - `SORT_IMPL_FUNC`:
+ * Function name of the sort function.
+ *
+ * Optionally:
+ * - `SORT_IMPL_USE_THUNK`:
+ * Takes an argument for the sort function (like `qsort_r`).
+ */
+
+/* -------------------------------------------------------------------- */
+/* Handle External Defines */
+
+/* check we're not building directly */
+#if !defined(SORT_IMPL_LINKTYPE) || !defined(SORT_IMPL_FUNC)
+# error "This file can't be compiled directly, include in another source file"
+#endif
+
+#define list_node SORT_IMPL_LINKTYPE
+#define list_sort_do SORT_IMPL_FUNC
+
+#ifdef SORT_IMPL_LINKTYPE_DATA
+# define SORT_ARG(n) ((n)->SORT_IMPL_LINKTYPE_DATA)
+#else
+# define SORT_ARG(n) (n)
+#endif
+
+#ifdef SORT_IMPL_USE_THUNK
+# define THUNK_APPEND1(a, thunk) a, thunk
+# define THUNK_PREPEND2(thunk, a, b) thunk, a, b
+#else
+# define THUNK_APPEND1(a, thunk) a
+# define THUNK_PREPEND2(thunk, a, b) a, b
+#endif
+
+#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
+#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define _SORT_PREFIX(id) _CONCAT(SORT_IMPL_FUNC, _##id)
+
+/* local identifiers */
+#define SortInfo _SORT_PREFIX(SortInfo)
+#define CompareFn _SORT_PREFIX(CompareFn)
+#define init_sort_info _SORT_PREFIX(init_sort_info)
+#define merge_lists _SORT_PREFIX(merge_lists)
+#define sweep_up _SORT_PREFIX(sweep_up)
+#define insert_list _SORT_PREFIX(insert_list)
+
+typedef int (* CompareFn)(
+#ifdef SORT_IMPL_USE_THUNK
+ void *thunk,
+#endif
+ const void *,
+ const void *);
+
+
+/* -------------------------------------------------------------------- */
+/* MIT license from original source */
+
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Raja R Harinath (rharinath@novell.com)
+ */
+
+/**
+ * The maximum possible depth of the merge tree
+ * - `ceiling(log2(maximum number of list nodes))`
+ * - `ceiling(log2(maximum possible memory size/size of each list node))`
+ * - number of bits in `'size_t' - floor(log2(sizeof(list_node *)))`
+ *
+ * Also, each list in #SortInfo is at least 2 nodes long:
+ * we can reduce the depth by 1.
+ */
+#define FLOOR_LOG2(x) \
+ (((x) >= 2) + ((x) >= 4) + ((x) >= 8) + ((x) >= 16) + ((x) >= 32) + ((x) >= 64) + ((x) >= 128))
+#define MAX_RANKS \
+ ((sizeof(size_t) * 8) - FLOOR_LOG2(sizeof(list_node)) - 1)
+
+struct SortInfo {
+ unsigned int min_rank, n_ranks;
+ CompareFn func;
+
+#ifdef SORT_IMPL_USE_THUNK
+ void *thunk;
+#endif
+
+ /**
+ * Invariant: `ranks[i] == NULL || length(ranks[i]) >= 2**(i+1)`.
+ *
+ * ~ 128 bytes on 32bit, ~ 512 bytes on 64bit */
+ list_node *ranks[MAX_RANKS];
+};
+
+BLI_INLINE void init_sort_info(
+ struct SortInfo *si,
+ CompareFn func
+#ifdef SORT_IMPL_USE_THUNK
+ ,
+ void *thunk
+#endif
+ )
+{
+ si->min_rank = si->n_ranks = 0;
+ si->func = func;
+ /* we don't need to initialize si->ranks,
+ * since we never lookup past si->n_ranks. */
+
+#ifdef SORT_IMPL_USE_THUNK
+ si->thunk = thunk;
+#endif
+}
+
+BLI_INLINE list_node *merge_lists(
+ list_node *first, list_node *second,
+ CompareFn func
+#ifdef SORT_IMPL_USE_THUNK
+ ,
+ void *thunk
+#endif
+ )
+{
+ /* merge the two lists */
+ list_node *list = NULL;
+ list_node **pos = &list;
+ while (first && second) {
+ if (func(THUNK_PREPEND2(thunk, SORT_ARG(first), SORT_ARG(second))) > 0) {
+ *pos = second;
+ second = second->next;
+ }
+ else {
+ *pos = first;
+ first = first->next;
+ }
+ pos = &((*pos)->next);
+ }
+ *pos = first ? first : second;
+ return list;
+}
+
+/**
+ * Pre-condition:
+ * `upto <= si->n_ranks, list == NULL || length(list) == 1`
+ */
+BLI_INLINE list_node *sweep_up(struct SortInfo *si, list_node *list, unsigned int upto)
+{
+ unsigned int i;
+ for (i = si->min_rank; i < upto; i++) {
+ list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk));
+ si->ranks[i] = NULL;
+ }
+ return list;
+}
+
+/**
+ * The 'ranks' array essentially captures the recursion stack of a mergesort.
+ * The merge tree is built in a bottom-up manner. The control loop for
+ * updating the 'ranks' array is analogous to incrementing a binary integer,
+ * and the `O(n)` time for counting upto n translates to `O(n)` merges when
+ * inserting `rank-0` lists.
+ * When we plug in the sizes of the lists involved in those merges,
+ * we get the `O(n log n)` time for the sort.
+ *
+ * Inserting higher-ranked lists reduce the height of the merge tree,
+ * and also eliminate a lot of redundant comparisons when merging two lists
+ * that would've been part of the same run.
+ * Adding a `rank-i` list is analogous to incrementing a binary integer by
+ * `2**i` in one operation, thus sharing a similar speedup.
+ *
+ * When inserting higher-ranked lists, we choose to clear out the lower ranks
+ * in the interests of keeping the sort stable, but this makes analysis harder.
+ * Note that clearing the lower-ranked lists is `O(length(list))--` thus it
+ * shouldn't affect the `O(n log n)` behaviour.
+ * In other words, inserting one `rank-i` list is equivalent to inserting
+ * `2**i` `rank-0` lists, thus even if we do `i` additional merges
+ * in the clearing-out (taking at most `2**i` time) we are still fine.
+ */
+
+/**
+ * Pre-condition:
+ * `2**(rank+1) <= length(list) < 2**(rank+2)`
+ * (therefore: `length(list) >= 2`)
+ */
+BLI_INLINE void insert_list(
+ struct SortInfo *si,
+ list_node *list,
+ unsigned int rank)
+{
+ unsigned int i;
+
+ if (rank > si->n_ranks) {
+ if (UNLIKELY(rank > MAX_RANKS)) {
+ // printf("Rank '%d' should not exceed " STRINGIFY(MAX_RANKS), rank);
+ rank = MAX_RANKS;
+ }
+ list = merge_lists(sweep_up(si, NULL, si->n_ranks), list, THUNK_APPEND1(si->func, si->thunk));
+ for (i = si->n_ranks; i < rank; ++i) {
+ si->ranks[i] = NULL;
+ }
+ }
+ else {
+ if (rank) {
+ list = merge_lists(sweep_up(si, NULL, rank), list, THUNK_APPEND1(si->func, si->thunk));
+ }
+ for (i = rank; i < si->n_ranks && si->ranks[i]; ++i) {
+ list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk));
+ si->ranks[i] = NULL;
+ }
+ }
+
+ /* Will _never_ happen: so we can just devolve into quadratic ;-) */
+ if (UNLIKELY(i == MAX_RANKS)) {
+ i--;
+ }
+
+ if (i >= si->n_ranks) {
+ si->n_ranks = i + 1;
+ }
+
+ si->min_rank = i;
+ si->ranks[i] = list;
+}
+
+#undef MAX_RANKS
+#undef FLOOR_LOG2
+
+/**
+ * Main sort function.
+ */
+BLI_INLINE list_node *list_sort_do(
+ list_node *list,
+ CompareFn func
+#ifdef SORT_IMPL_USE_THUNK
+ ,
+ void *thunk
+#endif
+ )
+{
+ struct SortInfo si;
+
+ init_sort_info(
+ &si,
+ func
+#ifdef SORT_IMPL_USE_THUNK
+ ,
+ thunk
+#endif
+ );
+
+ while (list && list->next) {
+ list_node *next = list->next;
+ list_node *tail = next->next;
+
+ if (func(THUNK_PREPEND2(thunk, SORT_ARG(list), SORT_ARG(next))) > 0) {
+ next->next = list;
+ next = list;
+ list = list->next;
+ }
+ next->next = NULL;
+
+ insert_list(&si, list, 0);
+
+ list = tail;
+ }
+
+ return sweep_up(&si, list, si.n_ranks);
+}
+
+#undef _CONCAT_AUX
+#undef _CONCAT
+#undef _SORT_PREFIX
+
+#undef SortInfo
+#undef CompareFn
+#undef init_sort_info
+#undef merge_lists
+#undef sweep_up
+#undef insert_list
+
+#undef list_node
+#undef list_sort_do
+
+#undef THUNK_APPEND1
+#undef THUNK_PREPEND2
+#undef SORT_ARG
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index d52c09790f9..ebee2c7941c 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -42,6 +42,8 @@
#include "BLI_listbase.h"
+#include "BLI_strict_flags.h"
+
/* implementation */
/**
@@ -205,53 +207,56 @@ void BLI_freelinkN(ListBase *listbase, void *vlink)
MEM_freeN(link);
}
+/**
+ * Assigns all #Link.prev pointers from #Link.next
+ */
+static void listbase_double_from_single(Link *iter, ListBase *listbase)
+{
+ Link *prev = NULL;
+ listbase->first = iter;
+ do {
+ iter->prev = prev;
+ prev = iter;
+ } while ((iter = iter->next));
+ listbase->last = prev;
+}
+
+#define SORT_IMPL_LINKTYPE Link
+
+/* regular call */
+#define SORT_IMPL_FUNC listbase_sort_fn
+#include "list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+
+/* reentrant call */
+#define SORT_IMPL_USE_THUNK
+#define SORT_IMPL_FUNC listbase_sort_fn_r
+#include "list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+#undef SORT_IMPL_USE_THUNK
+
+#undef SORT_IMPL_LINKTYPE
/**
* Sorts the elements of listbase into the order defined by cmp
- * (which should return 1 iff its first arg should come after its second arg).
+ * (which should return 1 if its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{
- Link *current = NULL;
- Link *previous = NULL;
- Link *next = NULL;
-
if (listbase->first != listbase->last) {
- for (previous = listbase->first, current = previous->next; current; current = next) {
- next = current->next;
- previous = current->prev;
-
- BLI_remlink(listbase, current);
-
- while (previous && cmp(previous, current) == 1) {
- previous = previous->prev;
- }
-
- BLI_insertlinkafter(listbase, previous, current);
- }
+ Link *head = listbase->first;
+ head = listbase_sort_fn(head, cmp);
+ listbase_double_from_single(head, listbase);
}
}
-void BLI_listbase_sort_r(ListBase *listbase, void *thunk, int (*cmp)(void *, const void *, const void *))
+void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk)
{
- Link *current = NULL;
- Link *previous = NULL;
- Link *next = NULL;
-
if (listbase->first != listbase->last) {
- for (previous = listbase->first, current = previous->next; current; current = next) {
- next = current->next;
- previous = current->prev;
-
- BLI_remlink(listbase, current);
-
- while (previous && cmp(thunk, previous, current) == 1) {
- previous = previous->prev;
- }
-
- BLI_insertlinkafter(listbase, previous, current);
- }
+ Link *head = listbase->first;
+ head = listbase_sort_fn_r(head, cmp, thunk);
+ listbase_double_from_single(head, listbase);
}
}
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 3ff1af3513e..0a1e9e8a8a1 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -31,41 +31,20 @@
#include "BLI_strict_flags.h"
-/* WARNING: MSVC compiling hack for double_round() */
-#if (defined(WIN32) || defined(WIN64)) && !(defined(FREE_WINDOWS))
-
-/* from python 3.1 pymath.c */
-double copysign(double x, double y)
+int pow_i(int base, int exp)
{
- /* use atan2 to distinguish -0.0 from 0.0 */
- if (y > 0.0 || (y == 0.0 && atan2(y, -1.0) > 0.0)) {
- return fabs(x);
- }
- else {
- return -fabs(x);
+ int result = 1;
+ BLI_assert(exp >= 0);
+ while (exp) {
+ if (exp & 1) {
+ result *= base;
+ }
+ exp >>= 1;
+ base *= base;
}
-}
-/* from python 3.1 pymath.c */
-double round(double x)
-{
- double absx, y;
- absx = fabs(x);
- y = floor(absx);
- if (absx - y >= 0.5)
- y += 1.0;
- return copysign(y, x);
+ return result;
}
-#else /* OpenSuse 11.1 seems to need this. */
-# ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wredundant-decls"
-# endif
-double round(double x);
-# ifdef __GNUC__
-# pragma GCC diagnostic pop
-# endif
-#endif
/* from python 3.1 floatobject.c
* ndigits must be between 0 and 21 */
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index f5713824296..facee8b0a89 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -198,25 +198,6 @@ MINLINE int mod_i(int i, int n)
return (i % n + n) % n;
}
-MINLINE unsigned int highest_order_bit_i(unsigned int n)
-{
- n |= (n >> 1);
- n |= (n >> 2);
- n |= (n >> 4);
- n |= (n >> 8);
- n |= (n >> 16);
- return n - (n >> 1);
-}
-
-MINLINE unsigned short highest_order_bit_s(unsigned short n)
-{
- n |= (n >> 1);
- n |= (n >> 2);
- n |= (n >> 4);
- n |= (n >> 8);
- return (unsigned short)(n - (n >> 1));
-}
-
MINLINE float min_ff(float a, float b)
{
return (a < b) ? a : b;
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
new file mode 100644
index 00000000000..11ee6e7fa5b
--- /dev/null
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+/** \file blender/blenlib/intern/math_bits_inline.c
+ * \ingroup bli
+ */
+
+#ifndef __MATH_BITS_INLINE_C__
+#define __MATH_BITS_INLINE_C__
+
+#include "BLI_math_bits.h"
+
+MINLINE unsigned int highest_order_bit_i(unsigned int n)
+{
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+ return n - (n >> 1);
+}
+
+MINLINE unsigned short highest_order_bit_s(unsigned short n)
+{
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ return (unsigned short)(n - (n >> 1));
+}
+
+#ifndef __GNUC__
+MINLINE int count_bits_i(unsigned int i)
+{
+ /* variable-precision SWAR algorithm. */
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+}
+#endif
+
+#endif /* __MATH_BITS_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index dc62d04ad55..45466226e72 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -200,60 +200,46 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
r_col[2] = ((pack) >> 16) & 0xFF;
}
-/* TODO:
+
+/** \name RGB/Grayscale Functions
*
- * regarding #rgb_to_bw vs #rgb_to_grayscale,
- * it seems nobody knows why we have both functions which convert color to grays
- * but with different influences, this is quite stupid, and should be resolved
- * by someone who knows this stuff: see this thread
- * http://lists.blender.org/pipermail/bf-committers/2012-June/037180.html
+ * \warning
+ * These are only an approximation,
+ * in almost _all_ cases, #IMB_colormanagement_get_luminance should be used instead.
+ * however for screen-only colors which don't depend on the currently loaded profile - this is preferred.
+ * Checking theme colors for contrast, etc. Basically anything outside the render pipeline.
*
- * Only conclusion is that rgb_to_grayscale is used more for compositing.
- */
-MINLINE float rgb_to_bw(const float rgb[3])
-{
- return 0.35f * rgb[0] + 0.45f * rgb[1] + 0.2f * rgb[2];
-}
+ * \{ */
-/* non-linear luma from ITU-R BT.601-2
- * see: http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC11
- * note: the values used for are not exact matches to those documented above,
- * but they are from the same */
+/**
+ * ITU-R BT.709 primaries
+ * http://en.wikipedia.org/wiki/Relative_luminance
+ *
+ * Real values are:
+ * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)``
+ * according to: "Derivation of Basic Television Color Equations", RP 177-1993
+ *
+ * As this sums slightly above 1.0, the document recommends to use:
+ * ``0.2126(R) + 0.7152(G) + 0.0722(B)``, as used here.
+ *
+ * The high precision values are used to calculate the rounded byte weights so they add up to 255:
+ * ``54(R) + 182(G) + 19(B)``
+ */
MINLINE float rgb_to_grayscale(const float rgb[3])
{
- return 0.3f * rgb[0] + 0.58f * rgb[1] + 0.12f * rgb[2];
+ return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
}
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3])
{
- return (unsigned char)(((76 * (unsigned short)rgb[0]) +
- (148 * (unsigned short)rgb[1]) +
- (31 * (unsigned short)rgb[2])) / 255);
+ return (unsigned char)(((54 * (unsigned short)rgb[0]) +
+ (182 * (unsigned short)rgb[1]) +
+ (19 * (unsigned short)rgb[2])) / 255);
}
-/* luma from defined by 'YCC_JFIF', see #rgb_to_ycc */
-MINLINE float rgb_to_luma(const float rgb[3])
-{
- return 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
-}
+/** \} */
-MINLINE unsigned char rgb_to_luma_byte(const unsigned char rgb[3])
-{
- return (unsigned char)(((76 * (unsigned short)rgb[0]) +
- (150 * (unsigned short)rgb[1]) +
- (29 * (unsigned short)rgb[2])) / 255);
-}
-/* gamma-corrected RGB --> CIE XYZ
- * for this function we only get the Y component
- * see: http://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch6/ch6_color_models.html
- *
- * also known as:
- * luminance rec. 709 */
-MINLINE float rgb_to_luma_y(const float rgb[3])
-{
- return 0.212671f * rgb[0] + 0.71516f * rgb[1] + 0.072169f * rgb[2];
-}
MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit)
{
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index ba1f4480659..7329a1177a8 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -442,6 +442,22 @@ float dist_squared_to_plane_v3(const float pt[3], const float plane[4])
return len_sq * (fac * fac);
}
+float dist_signed_squared_to_plane3_v3(const float pt[3], const float plane[3])
+{
+ const float len_sq = len_squared_v3(plane);
+ const float side = dot_v3v3(plane, pt); /* only difference with 'plane[4]' version */
+ const float fac = side / len_sq;
+ return copysignf(len_sq * (fac * fac), side);
+}
+float dist_squared_to_plane3_v3(const float pt[3], const float plane[3])
+{
+ const float len_sq = len_squared_v3(plane);
+ const float side = dot_v3v3(plane, pt); /* only difference with 'plane[4]' version */
+ const float fac = side / len_sq;
+ /* only difference to code above - no 'copysignf' */
+ return len_sq * (fac * fac);
+}
+
/**
* Return the signed distance from the point to the plane.
*/
@@ -457,6 +473,18 @@ float dist_to_plane_v3(const float pt[3], const float plane[4])
return fabsf(dist_signed_to_plane_v3(pt, plane));
}
+float dist_signed_to_plane3_v3(const float pt[3], const float plane[3])
+{
+ const float len_sq = len_squared_v3(plane);
+ const float side = dot_v3v3(plane, pt); /* only difference with 'plane[4]' version */
+ const float fac = side / len_sq;
+ return sqrtf(len_sq) * fac;
+}
+float dist_to_plane3_v3(const float pt[3], const float plane[3])
+{
+ return fabsf(dist_signed_to_plane3_v3(pt, plane));
+}
+
/* distance v1 to line-piece l1-l2 in 3D */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
{
@@ -514,9 +542,10 @@ float dist_signed_squared_to_corner_v3v3v3(
const float axis_ref[3])
{
float dir_a[3], dir_b[3];
- float plane_a[4], plane_b[4];
+ float plane_a[3], plane_b[3];
float dist_a, dist_b;
float axis[3];
+ float s_p_v2[3];
bool flip = false;
sub_v3_v3v3(dir_a, v1, v2);
@@ -537,16 +566,20 @@ float dist_signed_squared_to_corner_v3v3v3(
cross_v3_v3v3(plane_b, axis, dir_b);
#if 0
- plane_from_point_normal_v3(plane_a, center, l1);
- plane_from_point_normal_v3(plane_b, center, l2);
-#else
- /* do inline */
- plane_a[3] = -dot_v3v3(plane_a, v2);
- plane_b[3] = -dot_v3v3(plane_b, v2);
-#endif
+ plane_from_point_normal_v3(plane_a, v2, plane_a);
+ plane_from_point_normal_v3(plane_b, v2, plane_b);
dist_a = dist_signed_squared_to_plane_v3(p, plane_a);
dist_b = dist_signed_squared_to_plane_v3(p, plane_b);
+#else
+ /* calculate without he planes 4th component to avoid float precision issues */
+ sub_v3_v3v3(s_p_v2, p, v2);
+
+ dist_a = dist_signed_squared_to_plane3_v3(s_p_v2, plane_a);
+ dist_b = dist_signed_squared_to_plane3_v3(s_p_v2, plane_b);
+#endif
+
+
if (flip) {
return min_ff(dist_a, dist_b);
@@ -697,37 +730,73 @@ int isect_line_line_v2(const float v1[2], const float v2[2], const float v3[2],
* -1: collinear
* 1: intersection
*/
-int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], 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 r_vi[2])
{
- float a1, a2, b1, b2, c1, c2, d;
- float u, v;
+ float s10[2], s32[2], s30[2], d;
const float eps = 1e-6f;
const float eps_sq = eps * eps;
- a1 = v2[0] - v1[0];
- b1 = v4[0] - v3[0];
- c1 = v1[0] - v4[0];
+ sub_v2_v2v2(s10, v1, v0);
+ sub_v2_v2v2(s32, v3, v2);
+ sub_v2_v2v2(s30, v3, v0);
+
+ d = cross_v2v2(s10, s32);
+
+ if (d != 0) {
+ float u, v;
+
+ 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))
+ {
+ /* intersection */
+ float vi_test[2];
+ float s_vi_v2[2];
- a2 = v2[1] - v1[1];
- b2 = v4[1] - v3[1];
- c2 = v1[1] - v4[1];
+ madd_v2_v2v2fl(vi_test, v0, s10, u);
- d = a1 * b2 - a2 * b1;
+ /* When 'd' approaches zero, float precision lets non-overlapping co-linear segments
+ * detect as an intersection. So re-calculate 'v' to ensure the point overlaps both.
+ * see T45123 */
- if (d == 0) {
- if (a1 * c2 - a2 * c1 == 0.0f && b1 * c2 - b2 * c1 == 0.0f) { /* equal lines */
- float a[2], b[2], c[2];
- float u2;
+ /* inline since we have most vars already */
+#if 0
+ v = line_point_factor_v2(ix_test, v2, v3);
+#else
+ 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) {
+ copy_v2_v2(r_vi, vi_test);
+ return 1;
+ }
+ }
- if (equals_v2v2(v1, v2)) {
- if (len_squared_v2v2(v3, v4) > eps_sq) {
+ /* out of segment intersection */
+ return -1;
+ }
+ else {
+ if ((cross_v2v2(s10, s30) == 0.0f) &&
+ (cross_v2v2(s32, s30) == 0.0f))
+ {
+ /* equal lines */
+ float s20[2];
+ float u_a, u_b;
+
+ if (equals_v2v2(v0, v1)) {
+ if (len_squared_v2v2(v2, v3) > eps_sq) {
/* use non-point segment as basis */
+ SWAP(const float *, v0, v2);
SWAP(const float *, v1, v3);
- SWAP(const float *, v2, v4);
+
+ sub_v2_v2v2(s10, v1, v0);
+ sub_v2_v2v2(s30, v3, v0);
}
else { /* both of segments are points */
- if (equals_v2v2(v1, v3)) { /* points are equal */
- copy_v2_v2(vi, v1);
+ if (equals_v2v2(v0, v2)) { /* points are equal */
+ copy_v2_v2(r_vi, v0);
return 1;
}
@@ -736,19 +805,21 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[
}
}
- sub_v2_v2v2(a, v3, v1);
- sub_v2_v2v2(b, v2, v1);
- sub_v2_v2v2(c, v2, v1);
- u = dot_v2v2(a, b) / dot_v2v2(c, c);
+ sub_v2_v2v2(s20, v2, v0);
- sub_v2_v2v2(a, v4, v1);
- u2 = dot_v2v2(a, b) / dot_v2v2(c, c);
+ u_a = dot_v2v2(s20, s10) / dot_v2v2(s10, s10);
+ u_b = dot_v2v2(s30, s10) / dot_v2v2(s10, s10);
- if (u > u2) SWAP(float, u, u2);
+ if (u_a > u_b)
+ SWAP(float, u_a, u_b);
- if (u > 1.0f + eps || u2 < -eps) return -1; /* non-ovlerlapping segments */
- else if (max_ff(0.0f, u) == min_ff(1.0f, u2)) { /* one common point: can return result */
- interp_v2_v2v2(vi, v1, v2, max_ff(0, u));
+ if (u_a > 1.0f + eps || u_b < -eps) {
+ /* non-overlapping segments */
+ return -1;
+ }
+ else if (max_ff(0.0f, u_a) == min_ff(1.0f, u_b)) {
+ /* one common point: can return result */
+ madd_v2_v2v2fl(r_vi, v0, s10, max_ff(0, u_a));
return 1;
}
}
@@ -756,22 +827,13 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[
/* lines are collinear */
return -1;
}
-
- u = (c2 * b1 - b2 * c1) / d;
- v = (c1 * a2 - a1 * c2) / d;
-
- if (u >= -eps && u <= 1.0f + eps && v >= -eps && v <= 1.0f + eps) { /* intersection */
- interp_v2_v2v2(vi, v1, v2, u);
- return 1;
- }
-
- /* out of segment intersection */
- return -1;
}
bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
-#define CCW(A, B, C) ((C[1] - A[1]) * (B[0] - A[0]) > (B[1]-A[1]) * (C[0]-A[0]))
+#define CCW(A, B, C) \
+ ((C[1] - A[1]) * (B[0] - A[0]) > \
+ (B[1] - A[1]) * (C[0] - A[0]))
return CCW(v1, v3, v4) != CCW(v2, v3, v4) && CCW(v1, v2, v3) != CCW(v1, v2, v4);
@@ -2337,7 +2399,7 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
transpose_m3(r_mat);
BLI_assert(!is_negative_m3(r_mat));
- BLI_assert(fabsf(dot_m3_v3_row_z(r_mat, normal) - 1.0f) < BLI_ASSERT_UNIT_EPSILON);
+ BLI_assert((fabsf(dot_m3_v3_row_z(r_mat, normal) - 1.0f) < BLI_ASSERT_UNIT_EPSILON) || is_zero_v3(normal));
}
/****************************** Interpolation ********************************/
@@ -3101,6 +3163,43 @@ void resolve_quad_uv_v2_deriv(float r_uv[2], float r_deriv[2][2],
}
}
+/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
+float resolve_quad_u_v2(
+ const float st[2],
+ const float st0[2], const float st1[2], const float st2[2], const float st3[2])
+{
+ const double signed_area = (st0[0] * st1[1] - st0[1] * st1[0]) + (st1[0] * st2[1] - st1[1] * st2[0]) +
+ (st2[0] * st3[1] - st2[1] * st3[0]) + (st3[0] * st0[1] - st3[1] * st0[0]);
+
+ /* X is 2D cross product (determinant)
+ * A = (p0 - p) X (p0 - p3)*/
+ const double a = (st0[0] - st[0]) * (st0[1] - st3[1]) - (st0[1] - st[1]) * (st0[0] - st3[0]);
+
+ /* B = ( (p0 - p) X (p1 - p2) + (p1 - p) X (p0 - p3) ) / 2 */
+ const double b = 0.5 * (double)(((st0[0] - st[0]) * (st1[1] - st2[1]) - (st0[1] - st[1]) * (st1[0] - st2[0])) +
+ ((st1[0] - st[0]) * (st0[1] - st3[1]) - (st1[1] - st[1]) * (st0[0] - st3[0])));
+
+ /* C = (p1-p) X (p1-p2) */
+ const double fC = (st1[0] - st[0]) * (st1[1] - st2[1]) - (st1[1] - st[1]) * (st1[0] - st2[0]);
+ double denom = a - 2 * b + fC;
+
+ if (IS_ZERO(denom) != 0) {
+ const double fDen = a - fC;
+ if (IS_ZERO(fDen) == 0)
+ return (float)(a / fDen);
+ else
+ return 0.0f;
+ }
+ else {
+ const double desc_sq = b * b - a * fC;
+ const double desc = sqrt(desc_sq < 0.0 ? 0.0 : desc_sq);
+ const double s = signed_area > 0 ? (-1.0) : 1.0;
+
+ return (float)(((a - b) + s * desc) / denom);
+ }
+}
+
+
#undef IS_ZERO
/* reverse of the functions above */
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 67850463fe2..b45d8b4c13b 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -112,10 +112,10 @@ BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const fl
/* sample area entirely outside image? */
if (ceil(u) < 0 || floor(u) > width - 1 || ceil(v) < 0 || floor(v) > height - 1) {
if (float_output) {
- fill_vn_fl(float_output, components, 0.0f);
+ copy_vn_fl(float_output, components, 0.0f);
}
if (byte_output) {
- fill_vn_uchar(byte_output, components, 0);
+ copy_vn_uchar(byte_output, components, 0);
}
return;
}
@@ -281,7 +281,7 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
/* sample area entirely outside image? */
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
- fill_vn_fl(float_output, components, 0.0f);
+ copy_vn_fl(float_output, components, 0.0f);
return;
}
@@ -323,7 +323,7 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
/* sample area entirely outside image? */
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
- fill_vn_uchar(byte_output, components, 0);
+ copy_vn_uchar(byte_output, components, 0);
return;
}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 1b4bbafdb04..a9afed7a63d 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -504,6 +504,16 @@ void mul_mat3_m4_v3(float mat[4][4], float vec[3])
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
}
+void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3])
+{
+ const float x = vec[0];
+ const float y = vec[1];
+
+ r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
+ r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
+ r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
+}
+
void mul_project_m4_v3(float mat[4][4], float vec[3])
{
const float w = mul_project_m4_v3_zfac(mat, vec);
@@ -1149,7 +1159,7 @@ bool is_orthogonal_m3(float m[3][3])
for (i = 0; i < 3; i++) {
for (j = 0; j < i; j++) {
- if (fabsf(dot_v3v3(m[i], m[j])) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v3v3(m[i], m[j])) > 1e-5f)
return false;
}
}
@@ -1163,7 +1173,7 @@ bool is_orthogonal_m4(float m[4][4])
for (i = 0; i < 4; i++) {
for (j = 0; j < i; j++) {
- if (fabsf(dot_v4v4(m[i], m[j])) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v4v4(m[i], m[j])) > 1e-5f)
return false;
}
@@ -1178,7 +1188,7 @@ bool is_orthonormal_m3(float m[3][3])
int i;
for (i = 0; i < 3; i++)
- if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1e-5f)
return false;
return true;
@@ -1193,7 +1203,7 @@ bool is_orthonormal_m4(float m[4][4])
int i;
for (i = 0; i < 4; i++)
- if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1e-5f)
return false;
return true;
@@ -1465,39 +1475,14 @@ float mat4_to_scale(float mat[4][4])
void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3])
{
- float mat3_n[3][3]; /* mat3 -> normalized, 3x3 */
- float imat3_n[3][3]; /* mat3 -> normalized & inverted, 3x3 */
-
- /* rotation & scale are linked, we need to create the mat's
- * for these together since they are related. */
-
- /* so scale doesn't interfere with rotation [#24291] */
- /* note: this is a workaround for negative matrix not working for rotation conversion, FIXME */
- normalize_m3_m3(mat3_n, mat3);
- if (is_negative_m3(mat3)) {
- negate_m3(mat3_n);
- }
-
- /* rotation */
/* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */
- copy_m3_m3(rot, mat3_n);
-
- /* scale */
- /* note: mat4_to_size(ob->size, mat) fails for negative scale */
- invert_m3_m3(imat3_n, mat3_n);
-
- /* better not edit mat3 */
-#if 0
- mul_m3_m3m3(mat3, imat3_n, mat3);
-
- size[0] = mat3[0][0];
- size[1] = mat3[1][1];
- size[2] = mat3[2][2];
-#else
- size[0] = dot_m3_v3_row_x(imat3_n, mat3[0]);
- size[1] = dot_m3_v3_row_y(imat3_n, mat3[1]);
- size[2] = dot_m3_v3_row_z(imat3_n, mat3[2]);
-#endif
+ size[0] = normalize_v3_v3(rot[0], mat3[0]);
+ size[1] = normalize_v3_v3(rot[1], mat3[1]);
+ size[2] = normalize_v3_v3(rot[2], mat3[2]);
+ if (UNLIKELY(is_negative_m3(rot))) {
+ negate_m3(rot);
+ negate_v3(size);
+ }
}
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4])
@@ -2251,7 +2236,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon)
{
- /* compute moon-penrose pseudo inverse of matrix, singular values
+ /* compute Moore-Penrose pseudo inverse of matrix, singular values
* below epsilon are ignored for stability (truncated SVD) */
float A[4][4], V[4][4], W[4], Wm[4][4], U[4][4];
int i;
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 3d5d47bc2e0..5f039e89e89 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1043,11 +1043,12 @@ void expmap_to_quat(float r[4], const float expmap[3])
float angle;
/* Obtain axis/angle representation. */
- angle = normalize_v3_v3(axis, expmap);
- angle = angle_wrap_rad(angle);
-
- /* Convert to quaternion. */
- axis_angle_to_quat(r, axis, angle);
+ if (LIKELY((angle = normalize_v3_v3(axis, expmap)) != 0.0f)) {
+ axis_angle_normalized_to_quat(r, axis, angle_wrap_rad(angle));
+ }
+ else {
+ unit_qt(r);
+ }
}
/******************************** XYZ Eulers *********************************/
@@ -1322,12 +1323,21 @@ static const RotOrderInfo rotOrders[] = {
* NOTE: since we start at 1 for the values, but arrays index from 0,
* there is -1 factor involved in this process...
*/
-#define GET_ROTATIONORDER_INFO(order) (assert(order >= 0 && order <= 6), (order < 1) ? &rotOrders[0] : &rotOrders[(order) - 1])
+static const RotOrderInfo *get_rotation_order_info(const short order)
+{
+ assert(order >= 0 && order <= 6);
+ if (order < 1)
+ return &rotOrders[0];
+ else if (order < 6)
+ return &rotOrders[order - 1];
+ else
+ return &rotOrders[5];
+}
/* Construct quaternion from Euler angles (in radians). */
void eulO_to_quat(float q[4], const float e[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
double a[3];
@@ -1372,7 +1382,7 @@ void quat_to_eulO(float e[3], short const order, const float q[4])
/* Construct 3x3 matrix from Euler angles (in radians). */
void eulO_to_mat3(float M[3][3], const float e[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1413,7 +1423,7 @@ void eulO_to_mat3(float M[3][3], const float e[3], const short order)
/* returns two euler calculation methods, so we can pick the best */
static void mat3_to_eulo2(float M[3][3], float eul1[3], float eul2[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
float mat[3][3];
float cy;
@@ -1549,7 +1559,7 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang)
/* the matrix is written to as 3 axis vectors */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
float mat[3][3];
float teul[3];
@@ -1606,7 +1616,7 @@ void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order
void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4])
{
- float *t, *q, dscale[3], scale[3], basequat[4];
+ float *t, *q, dscale[3], scale[3], basequat[4], mat3[3][3];
float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4];
float R[4][4], S[4][4];
@@ -1619,7 +1629,9 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4])
dscale[1] = scale[1] - 1.0f;
dscale[2] = scale[2] - 1.0f;
- if ((determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) {
+ copy_m3_m4(mat3, mat);
+
+ if (!is_orthonormal_m3(mat3) || (determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) {
/* extract R and S */
float tmp[4][4];
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 814180bba24..6da0e87355d 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -572,6 +572,27 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
c[2] = mul * v2[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.
+ *
+ * \note If \a v is exactly perpendicular to \a v_plane, \a c will just be a copy of \a v.
+ */
+void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3])
+{
+ float delta[3];
+ project_v3_v3v3(delta, v, v_plane);
+ sub_v3_v3v3(c, v, delta);
+}
+
+void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2])
+{
+ float delta[2];
+ project_v2_v2v2(delta, v, v_plane);
+ sub_v2_v2v2(c, v, delta);
+}
+
/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float v[3], const float n[3], const float p[3])
{
@@ -855,7 +876,7 @@ float normalize_vn_vn(float *array_tar, const float *array_src, const int size)
mul_vn_vn_fl(array_tar, array_src, size, 1.0f / d_sqrt);
}
else {
- fill_vn_fl(array_tar, size, 0.0f);
+ copy_vn_fl(array_tar, size, 0.0f);
d_sqrt = 0.0f;
}
return d_sqrt;
@@ -876,6 +897,16 @@ void range_vn_i(int *array_tar, const int size, const int start)
}
}
+void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start)
+{
+ unsigned int *array_pt = array_tar + (size - 1);
+ unsigned int j = start + (unsigned int)(size - 1);
+ int i = size;
+ while (i--) {
+ *(array_pt--) = j--;
+ }
+}
+
void range_vn_fl(float *array_tar, const int size, const float start, const float step)
{
float *array_pt = array_tar + (size - 1);
@@ -1020,7 +1051,7 @@ void interp_vn_vn(float *array_tar, const float *array_src, const float t, const
}
}
-void fill_vn_i(int *array_tar, const int size, const int val)
+void copy_vn_i(int *array_tar, const int size, const int val)
{
int *tar = array_tar + (size - 1);
int i = size;
@@ -1029,7 +1060,7 @@ void fill_vn_i(int *array_tar, const int size, const int val)
}
}
-void fill_vn_short(short *array_tar, const int size, const short val)
+void copy_vn_short(short *array_tar, const int size, const short val)
{
short *tar = array_tar + (size - 1);
int i = size;
@@ -1038,7 +1069,7 @@ void fill_vn_short(short *array_tar, const int size, const short val)
}
}
-void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val)
+void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val)
{
unsigned short *tar = array_tar + (size - 1);
int i = size;
@@ -1047,7 +1078,7 @@ void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned sh
}
}
-void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val)
+void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val)
{
unsigned char *tar = array_tar + (size - 1);
int i = size;
@@ -1056,7 +1087,7 @@ void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char
}
}
-void fill_vn_fl(float *array_tar, const int size, const float val)
+void copy_vn_fl(float *array_tar, const int size, const float val)
{
float *tar = array_tar + (size - 1);
int i = size;
@@ -1064,3 +1095,38 @@ void fill_vn_fl(float *array_tar, const int size, const float val)
*(tar--) = val;
}
}
+
+/** \name Double precision versions 'db'.
+ * \{ */
+
+void add_vn_vn_d(double *array_tar, const double *array_src, const int size)
+{
+ double *tar = array_tar + (size - 1);
+ const double *src = array_src + (size - 1);
+ int i = size;
+ while (i--) {
+ *(tar--) += *(src--);
+ }
+}
+
+void add_vn_vnvn_d(double *array_tar, const double *array_src_a, const double *array_src_b, const int size)
+{
+ double *tar = array_tar + (size - 1);
+ const double *src_a = array_src_a + (size - 1);
+ const double *src_b = array_src_b + (size - 1);
+ int i = size;
+ while (i--) {
+ *(tar--) = *(src_a--) + *(src_b--);
+ }
+}
+
+void mul_vn_db(double *array_tar, const int size, const double f)
+{
+ double *array_pt = array_tar + (size - 1);
+ int i = size;
+ while (i--) {
+ *(array_pt--) *= f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 6b6a3113e0b..fb33fed33e4 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -611,6 +611,48 @@ MINLINE void negate_v3_short(short r[3])
r[2] = (short)-r[2];
}
+MINLINE void abs_v2(float r[2])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+}
+
+MINLINE void abs_v2_v2(float r[2], const float a[2])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+}
+
+MINLINE void abs_v3(float r[3])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+ r[2] = fabsf(r[2]);
+}
+
+MINLINE void abs_v3_v3(float r[3], const float a[3])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+ r[2] = fabsf(a[2]);
+}
+
+MINLINE void abs_v4(float r[4])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+ r[2] = fabsf(r[2]);
+ r[3] = fabsf(r[3]);
+}
+
+MINLINE void abs_v4_v4(float r[4], const float a[4])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+ r[2] = fabsf(a[2]);
+ r[3] = fabsf(a[3]);
+}
+
MINLINE float dot_v2v2(const float a[2], const float b[2])
{
return a[0] * b[0] + a[1] * b[1];
@@ -638,6 +680,11 @@ MINLINE float dot_v4v4(const float a[4], const float b[4])
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
+MINLINE double dot_v3db_v3fl(const double a[3], const float b[3])
+{
+ return a[0] * (double)b[0] + a[1] * (double)b[1] + a[2] * (double)b[2];
+}
+
MINLINE float cross_v2v2(const float a[2], const float b[2])
{
return a[0] * b[1] - a[1] * b[0];
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 72739018399..b1a7d74e46f 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -57,6 +57,9 @@
# include <shlobj.h>
# include "BLI_winstuff.h"
# include "MEM_guardedalloc.h"
+# include "BLI_alloca.h"
+#else
+# include "unistd.h"
#endif /* WIN32 */
/* local */
@@ -743,7 +746,7 @@ bool BLI_parent_dir(char *path)
BLI_cleanup_dir(NULL, tmp); /* does all the work of normalizing the path for us */
if (!BLI_testextensie(tmp, parent_dir)) {
- BLI_strncpy(path, tmp, sizeof(tmp));
+ strcpy(path, tmp); /* We assume pardir is always shorter... */
return true;
}
else {
@@ -856,6 +859,111 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
}
/**
+ * Get the frame from a filename formatted by blender's frame scheme
+ */
+bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
+{
+ if (path && *path) {
+ char *file = (char *)BLI_last_slash(path);
+ char *c;
+ int len, numdigits;
+
+ numdigits = *r_numdigits = 0;
+
+ if (file == NULL)
+ file = path;
+
+ /* first get the extension part */
+ len = strlen(file);
+
+ c = file + len;
+
+ /* isolate extension */
+ while (--c != file) {
+ if (*c == '.') {
+ c--;
+ break;
+ }
+ }
+
+ /* find start of number */
+ while (c != (file - 1) && isdigit(*c)) {
+ c--;
+ numdigits++;
+ }
+
+ if (numdigits) {
+ char prevchar;
+
+ c++;
+ prevchar = c[numdigits];
+ c[numdigits] = 0;
+
+ /* was the number really an extension? */
+ *r_frame = atoi(c);
+ c[numdigits] = prevchar;
+
+ *r_numdigits = numdigits;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BLI_path_frame_strip(char *path, bool setsharp, char *ext)
+{
+ if (path && *path) {
+ char *file = (char *)BLI_last_slash(path);
+ char *c, *suffix;
+ int len;
+ int numdigits = 0;
+
+ if (file == NULL)
+ file = path;
+
+ /* first get the extension part */
+ len = strlen(file);
+
+ c = file + len;
+
+ /* isolate extension */
+ while (--c != file) {
+ if (*c == '.') {
+ c--;
+ break;
+ }
+ }
+
+ suffix = c + 1;
+
+ /* find start of number */
+ while (c != (file - 1) && isdigit(*c)) {
+ c--;
+ numdigits++;
+ }
+
+ c++;
+
+ if (numdigits) {
+ /* replace the number with the suffix and terminate the string */
+ while (numdigits--) {
+ if (ext) *ext++ = *suffix;
+
+ if (setsharp) *c++ = '#';
+ else *c++ = *suffix;
+
+ suffix++;
+ }
+ *c = 0;
+ if (ext) *ext = 0;
+ }
+ }
+}
+
+
+/**
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
*/
bool BLI_path_frame_check_chars(const char *path)
@@ -1018,6 +1126,114 @@ bool BLI_path_cwd(char *path)
return wasrelative;
}
+#ifdef _WIN32
+/**
+ * Tries appending each of the semicolon-separated extensions in the PATHEXT
+ * environment variable (Windows-only) onto *name in turn until such a file is found.
+ * Returns success/failure.
+ */
+bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
+{
+ bool retval = false;
+ int type;
+
+ type = BLI_exists(name);
+ if ((type == 0) || S_ISDIR(type)) {
+ /* typically 3-5, ".EXE", ".BAT"... etc */
+ const int ext_max = 12;
+ const char *ext = getenv("PATHEXT");
+ if (ext) {
+ const int name_len = strlen(name);
+ char *filename = alloca(name_len + ext_max);
+ char *filename_ext;
+ const char *ext_next;
+
+ /* null terminated in the loop */
+ memcpy(filename, name, name_len);
+ filename_ext = filename + name_len;
+
+ do {
+ int ext_len;
+ ext_next = strchr(ext, ';');
+ ext_len = ext_next ? ((ext_next++) - ext) : strlen(ext);
+
+ if (LIKELY(ext_len < ext_max)) {
+ memcpy(filename_ext, ext, ext_len);
+ filename_ext[ext_len] = '\0';
+
+ type = BLI_exists(filename);
+ if (type && (!S_ISDIR(type))) {
+ retval = true;
+ BLI_strncpy(name, filename, maxlen);
+ break;
+ }
+ }
+ } while ((ext = ext_next));
+ }
+ }
+ else {
+ retval = true;
+ }
+
+ return retval;
+}
+#endif /* WIN32 */
+
+/**
+ * Search for a binary (executable)
+ */
+bool BLI_path_program_search(
+ char *fullname, const size_t maxlen,
+ const char *name)
+{
+ const char *path;
+ bool retval = false;
+
+#ifdef _WIN32
+ const char separator = ';';
+#else
+ const char separator = ':';
+#endif
+
+ path = getenv("PATH");
+ if (path) {
+ char filename[FILE_MAX];
+ const char *temp;
+
+ do {
+ temp = strchr(path, separator);
+ if (temp) {
+ strncpy(filename, path, temp - path);
+ filename[temp - path] = 0;
+ path = temp + 1;
+ }
+ else {
+ strncpy(filename, path, sizeof(filename));
+ }
+
+ BLI_path_append(filename, maxlen, name);
+ if (
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(filename, maxlen)
+#else
+ BLI_exists(filename)
+#endif
+ )
+ {
+ BLI_strncpy(fullname, filename, maxlen);
+ retval = true;
+ break;
+ }
+ } while (temp);
+ }
+
+ if (retval == false) {
+ *fullname = '\0';
+ }
+
+ return retval;
+}
+
/**
* Copies into *last the part of *dir following the second-last slash.
*/
@@ -1109,33 +1325,18 @@ void BLI_char_switch(char *string, char from, char to)
*/
void BLI_make_exist(char *dir)
{
- int a;
- char par_path[PATH_MAX + 3];
+ bool valid_path = true;
- BLI_char_switch(dir, ALTSEP, SEP);
+ /* Loop as long as cur path is not a dir, and we can get a parent path. */
+ while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir)));
- a = strlen(dir);
-
- for (BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT);
- !(BLI_is_dir(dir) && BLI_exists(par_path));
- BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT))
- {
- a--;
- while (dir[a] != SEP) {
- a--;
- if (a <= 0) break;
- }
- if (a >= 0) {
- dir[a + 1] = '\0';
- }
- else {
+ /* If we could not find an existing dir, use default root... */
+ if (!valid_path || !dir[0]) {
#ifdef WIN32
- get_default_root(dir);
+ get_default_root(dir);
#else
- strcpy(dir, "/");
+ strcpy(dir, "/");
#endif
- break;
- }
}
}
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 3aadbe5f1df..df6caa4b65a 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -61,6 +61,9 @@
# define USE_KDTREE
#endif
+/* disable in production, it can fail on near zero area ngons */
+// #define USE_STRICT_ASSERT
+
// #define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"
@@ -179,7 +182,7 @@ BLI_INLINE eSign signum_enum(float a)
* alternative version of #area_tri_signed_v2
* needed because of float precision issues
*
- * \note removes / 2 since its not needed since we only need ths sign.
+ * \note removes / 2 since its not needed since we only need the sign.
*/
BLI_INLINE float area_tri_signed_v2_alt_2x(const float v1[2], const float v2[2], const float v3[2])
{
@@ -797,6 +800,7 @@ static void polyfill_prepare(
}
else {
/* chech we're passing in correcty args */
+#ifdef USE_STRICT_ASSERT
#ifndef NDEBUG
if (coords_sign == 1) {
BLI_assert(cross_poly_v2(coords, coords_tot) >= 0.0f);
@@ -805,6 +809,7 @@ static void polyfill_prepare(
BLI_assert(cross_poly_v2(coords, coords_tot) <= 0.0f);
}
#endif
+#endif
}
if (coords_sign == 1) {
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index ba71f52b530..46f9251bea7 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -430,17 +430,19 @@ void BLI_polyfill_beautify(
}
if (!is_boundary_edge(e_pair[0], e_pair[1], coord_last)) {
- struct PolyEdge *e = BLI_edgehash_lookup(ehash, e_pair[0], e_pair[1]);
- if (e == NULL) {
+ struct PolyEdge *e;
+ void **val_p;
+
+ if (!BLI_edgehash_ensure_p(ehash, e_pair[0], e_pair[1], &val_p)) {
e = &edges[edges_tot_used++];
- BLI_edgehash_insert(ehash, e_pair[0], e_pair[1], e);
+ *val_p = e;
memcpy(e->verts, e_pair, sizeof(e->verts));
#ifndef NDEBUG
e->faces[!e_index] = (unsigned int)-1;
#endif
}
else {
-
+ e = *val_p;
/* ensure each edge only ever has 2x users */
#ifndef NDEBUG
BLI_assert(e->faces[e_index] == (unsigned int)-1);
diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c
index 814d05ca80e..588cd9c2cb5 100644
--- a/source/blender/blenlib/intern/quadric.c
+++ b/source/blender/blenlib/intern/quadric.c
@@ -29,20 +29,24 @@
* \note This isn't fully complete,
* possible there are other useful functions to add here.
*
- * \note try to follow BLI_math naming convention here.
+ * \note follow BLI_math naming convention here.
+ *
+ * \note this uses doubles for internal calculations,
+ * even though input/output are floats in some cases.
+ *
+ * This is done because the cases quadrics are useful
+ * often need high precision, see T44780.
*/
-//#include <string.h>
-
#include "BLI_math.h"
#include "BLI_strict_flags.h"
#include "BLI_quadric.h" /* own include */
-#define QUADRIC_FLT_TOT (sizeof(Quadric) / sizeof(float))
+#define QUADRIC_FLT_TOT (sizeof(Quadric) / sizeof(double))
-void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset)
+void BLI_quadric_from_plane(Quadric *q, const double v[4])
{
q->a2 = v[0] * v[0];
q->b2 = v[1] * v[1];
@@ -52,33 +56,33 @@ void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset)
q->ac = v[0] * v[2];
q->bc = v[1] * v[2];
- q->ad = v[0] * offset;
- q->bd = v[1] * offset;
- q->cd = v[2] * offset;
+ q->ad = v[0] * v[3];
+ q->bd = v[1] * v[3];
+ q->cd = v[2] * v[3];
- q->d2 = offset * offset;
+ q->d2 = v[3] * v[3];
}
void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3])
{
- m[0][0] = q->a2;
- m[0][1] = q->ab;
- m[0][2] = q->ac;
+ m[0][0] = (float)q->a2;
+ m[0][1] = (float)q->ab;
+ m[0][2] = (float)q->ac;
- m[1][0] = q->ab;
- m[1][1] = q->b2;
- m[1][2] = q->bc;
+ m[1][0] = (float)q->ab;
+ m[1][1] = (float)q->b2;
+ m[1][2] = (float)q->bc;
- m[2][0] = q->ac;
- m[2][1] = q->bc;
- m[2][2] = q->c2;
+ m[2][0] = (float)q->ac;
+ m[2][1] = (float)q->bc;
+ m[2][2] = (float)q->c2;
}
void BLI_quadric_to_vector_v3(const Quadric *q, float v[3])
{
- v[0] = q->ad;
- v[1] = q->bd;
- v[2] = q->cd;
+ v[0] = (float)q->ad;
+ v[1] = (float)q->bd;
+ v[2] = (float)q->cd;
}
void BLI_quadric_clear(Quadric *q)
@@ -88,25 +92,26 @@ void BLI_quadric_clear(Quadric *q)
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b)
{
- add_vn_vn((float *)a, (float *)b, QUADRIC_FLT_TOT);
+ add_vn_vn_d((double *)a, (double *)b, QUADRIC_FLT_TOT);
}
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b)
{
- add_vn_vnvn((float *)r, (const float *)a, (const float *)b, QUADRIC_FLT_TOT);
+ add_vn_vnvn_d((double *)r, (const double *)a, (const double *)b, QUADRIC_FLT_TOT);
}
-void BLI_quadric_mul(Quadric *a, const float scalar)
+void BLI_quadric_mul(Quadric *a, const double scalar)
{
- mul_vn_fl((float *)a, QUADRIC_FLT_TOT, scalar);
+ mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar);
}
-float BLI_quadric_evaluate(const Quadric *q, const float v[3])
+double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3])
{
- return (v[0] * v[0] * q->a2 + 2.0f * v[0] * v[1] * q->ab + 2.0f * v[0] * v[2] * q->ac + 2.0f * v[0] * q->ad +
- v[1] * v[1] * q->b2 + 2.0f * v[1] * v[2] * q->bc + 2.0f * v[1] * q->bd +
- v[2] * v[2] * q->c2 + 2.0f * v[2] * q->cd +
- q->d2);
+ const double v[3] = {UNPACK3(v_fl)};
+ return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) +
+ (q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) +
+ (q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) +
+ (q->d2));
}
bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon)
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index a03b236b5c6..66c568a7ff3 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -68,6 +68,9 @@ RNG *BLI_rng_new(unsigned int seed)
return rng;
}
+/**
+ * A version of #BLI_rng_new that hashes the seed.
+ */
RNG *BLI_rng_new_srandom(unsigned int seed)
{
RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
@@ -87,6 +90,9 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
rng->X = (((uint64_t) seed) << 16) | LOWSEED;
}
+/**
+ * Use a hash table to create better seed.
+ */
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
BLI_rng_seed(rng, seed + hash[seed & 255]);
@@ -113,11 +119,17 @@ unsigned int BLI_rng_get_uint(RNG *rng)
return (unsigned int) (rng->X >> 17);
}
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
double BLI_rng_get_double(RNG *rng)
{
return (double) BLI_rng_get_int(rng) / 0x80000000;
}
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
float BLI_rng_get_float(RNG *rng)
{
return (float) BLI_rng_get_int(rng) / 0x80000000;
@@ -172,7 +184,7 @@ void BLI_rng_get_tri_sample_float_v2(
void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot)
{
- const size_t elem_size = (unsigned int)elem_size_i;
+ const size_t elem_size = (size_t)elem_size_i;
unsigned int i = elem_tot;
void *temp;
@@ -196,6 +208,11 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig
free(temp);
}
+/**
+ * Simulate getting \a n random values.
+ *
+ * \note Useful when threaded code needs consistent values, independent of task division.
+ */
void BLI_rng_skip(RNG *rng, int n)
{
while (n--) {
@@ -208,7 +225,6 @@ void BLI_rng_skip(RNG *rng, int n)
/* initialize with some non-zero seed */
static RNG theBLI_rng = {611330372042337130};
-/* using hash table to create better seed */
void BLI_srandom(unsigned int seed)
{
BLI_rng_srandom(&theBLI_rng, seed);
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 61e5783cd3e..8de5d2ef172 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -123,6 +123,38 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
}
/**
+ * \returns shortest distance from \a rect to x/y (0 if inside)
+*/
+
+int BLI_rcti_length_x(const rcti *rect, const int x)
+{
+ if (x < rect->xmin) return rect->xmin - x;
+ if (x > rect->xmax) return x - rect->xmax;
+ return 0;
+}
+
+int BLI_rcti_length_y(const rcti *rect, const int y)
+{
+ if (y < rect->ymin) return rect->ymin - y;
+ if (y > rect->ymax) return y - rect->ymax;
+ return 0;
+}
+
+float BLI_rctf_length_x(const rctf *rect, const float x)
+{
+ if (x < rect->xmin) return rect->xmin - x;
+ if (x > rect->xmax) return x - rect->xmax;
+ return 0.0f;
+}
+
+float BLI_rctf_length_y(const rctf *rect, const float y)
+{
+ if (y < rect->ymin) return rect->ymin - y;
+ if (y > rect->ymax) return y - rect->ymax;
+ return 0.0f;
+}
+
+/**
* is \a rct_b inside \a rct_a
*/
bool BLI_rctf_inside_rctf(rctf *rct_a, const rctf *rct_b)
@@ -571,3 +603,46 @@ void print_rcti(const char *str, const rcti *rect)
printf("%s: xmin %d, xmax %d, ymin %d, ymax %d (%dx%d)\n", str,
rect->xmin, rect->xmax, rect->ymin, rect->ymax, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
}
+
+
+/* -------------------------------------------------------------------- */
+/* Comprehensive math (float only) */
+
+/** \name Rect math functions
+ * \{ */
+
+#define ROTATE_SINCOS(r_vec, mat2, vec) { \
+ (r_vec)[0] = (mat2)[1] * (vec)[0] + (+(mat2)[0]) * (vec)[1]; \
+ (r_vec)[1] = (mat2)[0] * (vec)[0] + (-(mat2)[1]) * (vec)[1]; \
+} ((void)0)
+
+/**
+ * Expand the rectangle to fit a rotated \a src.
+ */
+void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
+{
+ const float mat2[2] = {sinf(angle), cosf(angle)};
+ const float cent[2] = {BLI_rctf_cent_x(src), BLI_rctf_cent_y(src)};
+ float corner[2], corner_rot[2], corder_max[2];
+
+ /* x is same for both corners */
+ corner[0] = src->xmax - cent[0];
+ corner[1] = src->ymax - cent[1];
+ ROTATE_SINCOS(corner_rot, mat2, corner);
+ corder_max[0] = fabsf(corner_rot[0]);
+ corder_max[1] = fabsf(corner_rot[1]);
+
+ corner[1] *= -1;
+ ROTATE_SINCOS(corner_rot, mat2, corner);
+ corder_max[0] = MAX2(corder_max[0], fabsf(corner_rot[0]));
+ corder_max[1] = MAX2(corder_max[1], fabsf(corner_rot[1]));
+
+ dst->xmin = cent[0] - corder_max[0];
+ dst->xmax = cent[0] + corder_max[0];
+ dst->ymin = cent[1] - corder_max[1];
+ dst->ymax = cent[1] + corder_max[1];
+}
+
+#undef ROTATE_SINCOS
+
+/** \} */
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index a606ac41aa1..059d5cb05a4 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -112,11 +112,13 @@ void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx)
static ListBase *edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed)
{
ListBase *e_ls;
- e_ls = BLI_ghash_lookup(isect_hash, eed);
- if (e_ls == NULL) {
- e_ls = MEM_callocN(sizeof(ListBase), __func__);
- BLI_ghash_insert(isect_hash, eed, e_ls);
+ void **val_p;
+
+ if (!BLI_ghash_ensure_p(isect_hash, eed, &val_p)) {
+ *val_p = MEM_callocN(sizeof(ListBase), __func__);
}
+ e_ls = *val_p;
+
return e_ls;
}
@@ -265,7 +267,7 @@ static bool scanfill_preprocess_self_isect(
}
if (BLI_listbase_is_single(e_ls) == false) {
- BLI_listbase_sort_r(e_ls, eed->v2->co, edge_isect_ls_sort_cb);
+ BLI_listbase_sort_r(e_ls, edge_isect_ls_sort_cb, eed->v2->co);
}
/* move original edge to filledgebase and add replacement
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 2d3a2f77a3e..084d692fcf0 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -125,8 +125,10 @@ void BLI_stack_free(BLI_Stack *stack)
}
/**
- * Copies the source value onto the stack (note that it copies
- * elem_size bytes from 'src', the pointer itself is not stored)
+ * Push a new item onto the stack.
+ *
+ * \return a pointer #BLI_Stack.elem_size
+ * bytes of uninitialized memory (caller must fill in).
*/
void *BLI_stack_push_r(BLI_Stack *stack)
{
@@ -158,6 +160,14 @@ void *BLI_stack_push_r(BLI_Stack *stack)
return CHUNK_LAST_ELEM(stack);
}
+/**
+ * Copies the source value onto the stack
+ *
+ * \note This copies #BLI_Stack.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the stack.
+ */
void BLI_stack_push(BLI_Stack *stack, const void *src)
{
void *dst = BLI_stack_push_r(stack);
@@ -179,6 +189,15 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
BLI_stack_discard(stack);
}
+/**
+ * A version of #BLI_stack_pop which which fills in an array.
+ *
+ * \param dst: The destination array,
+ * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
+ * \param n: The number of items to pop.
+ *
+ * \note The first item in the array will be last item added to the stack.
+ */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -189,6 +208,23 @@ void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
}
}
+/**
+ * A version of #BLI_stack_pop_n which which fills in an array (in the reverse order).
+ *
+ * \note The first item in the array will be first item added to the stack.
+ */
+void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n)
+{
+ BLI_assert(n <= BLI_stack_count(stack));
+
+ dst = (void *)((char *)dst + (stack->elem_size * n));
+
+ while (n--) {
+ dst = (void *)((char *)dst - stack->elem_size);
+ BLI_stack_pop(stack, dst);
+ }
+}
+
void *BLI_stack_peek(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -196,6 +232,9 @@ void *BLI_stack_peek(BLI_Stack *stack)
return CHUNK_LAST_ELEM(stack);
}
+/**
+ * Removes the top element from the stack.
+ */
void BLI_stack_discard(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -216,6 +255,41 @@ void BLI_stack_discard(BLI_Stack *stack)
}
}
+/**
+ * Discards all elements without freeing.
+ */
+void BLI_stack_clear(BLI_Stack *stack)
+{
+#ifdef USE_TOTELEM
+ if (UNLIKELY(stack->totelem == 0)) {
+ return;
+ }
+ stack->totelem = 0;
+#else
+ if (UNLIKELY(stack->chunk_curr == NULL)) {
+ return;
+ }
+#endif
+
+ stack->chunk_index = stack->chunk_elem_max - 1;
+
+ if (stack->chunk_free) {
+ if (stack->chunk_curr) {
+ /* move all used chunks into tail of free list */
+ struct StackChunk *chunk_free_last = stack->chunk_free;
+ while (chunk_free_last->next) {
+ chunk_free_last = chunk_free_last->next;
+ }
+ chunk_free_last->next = stack->chunk_curr;
+ stack->chunk_curr = NULL;
+ }
+ }
+ else {
+ stack->chunk_free = stack->chunk_curr;
+ stack->chunk_curr = NULL;
+ }
+}
+
size_t BLI_stack_count(const BLI_Stack *stack)
{
#ifdef USE_TOTELEM
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 46c5a11949c..7fdf6ec8101 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -35,11 +35,6 @@
#include <stdio.h>
#include <stdlib.h>
-#ifndef WIN32
-# include <dirent.h>
-#endif
-
-#include <time.h>
#include <sys/stat.h>
#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || defined(__sun)
@@ -79,17 +74,13 @@
/* lib includes */
#include "MEM_guardedalloc.h"
-#include "DNA_listBase.h"
-
-#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
#include "BLI_linklist.h"
#include "BLI_string.h"
#include "BLI_fileops.h"
#include "BLI_fileops_types.h"
#include "BLI_path_util.h"
-#include "../imbuf/IMB_imbuf.h"
-
/**
* Copies the current working directory into *dir (max size maxncpy), and
* returns a pointer to same.
@@ -107,42 +98,6 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
return getcwd(dir, maxncpy);
}
-/*
- * Ordering function for sorting lists of files/directories. Returns -1 if
- * entry1 belongs before entry2, 0 if they are equal, 1 if they should be swapped.
- */
-static int bli_compare(struct direntry *entry1, struct direntry *entry2)
-{
- /* type is equal to stat.st_mode */
-
- /* directories come before non-directories */
- if (S_ISDIR(entry1->type)) {
- if (S_ISDIR(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISDIR(entry2->type)) return (1);
- }
- /* non-regular files come after regular files */
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISREG(entry2->type)) return (1);
- }
- /* arbitrary, but consistent, ordering of different types of non-regular files */
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
-
- /* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
- /* make sure "." and ".." are always first */
- if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
- if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
- if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
- if (FILENAME_IS_PARENT(entry2->relname)) return (1);
-
- return (BLI_natstrcmp(entry1->relname, entry2->relname));
-}
-
/**
* Returns the number of free bytes on the volume containing the specified pathname. */
/* Not actually used anywhere.
@@ -204,267 +159,6 @@ double BLI_dir_free_space(const char *dir)
#endif
}
-struct BuildDirCtx {
- struct direntry *files; /* array[nrfiles] */
- int nrfiles;
-};
-
-/**
- * Scans the directory named *dirname and appends entries for its contents to files.
- */
-static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
-{
- struct ListBase dirbase = {NULL, NULL};
- int newnum = 0;
- DIR *dir;
-
- if ((dir = opendir(dirname)) != NULL) {
- const struct dirent *fname;
- while ((fname = readdir(dir)) != NULL) {
- struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
- if (dlink != NULL) {
- dlink->name = BLI_strdup(fname->d_name);
- BLI_addhead(&dirbase, dlink);
- newnum++;
- }
- }
-
- if (newnum) {
- if (dir_ctx->files) {
- void * const tmp = MEM_reallocN(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
- if (tmp) {
- dir_ctx->files = (struct direntry *)tmp;
- }
- else { /* realloc fail */
- MEM_freeN(dir_ctx->files);
- dir_ctx->files = NULL;
- }
- }
-
- if (dir_ctx->files == NULL)
- dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry), __func__);
-
- if (dir_ctx->files) {
- struct dirlink * dlink = (struct dirlink *) dirbase.first;
- struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
- while (dlink) {
- char fullname[PATH_MAX];
- memset(file, 0, sizeof(struct direntry));
- file->relname = dlink->name;
- file->path = BLI_strdupcat(dirname, dlink->name);
- BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
- if (BLI_stat(fullname, &file->s) != -1) {
- file->type = file->s.st_mode;
- }
- file->flags = 0;
- dir_ctx->nrfiles++;
- file++;
- dlink = dlink->next;
- }
- }
- else {
- printf("Couldn't get memory for dir\n");
- exit(1);
- }
-
- BLI_freelist(&dirbase);
- if (dir_ctx->files) {
- qsort(dir_ctx->files, dir_ctx->nrfiles, sizeof(struct direntry), (int (*)(const void *, const void *))bli_compare);
- }
- }
- else {
- printf("%s empty directory\n", dirname);
- }
-
- closedir(dir);
- }
- else {
- printf("%s non-existent directory\n", dirname);
- }
-}
-
-/**
- * Fills in the "mode[123]", "size" and "string" fields in the elements of the files
- * array with descriptive details about each item. "string" will have a format similar to "ls -l".
- */
-static void bli_adddirstrings(struct BuildDirCtx *dir_ctx)
-{
- const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
- /* symbolic display, indexed by mode field value */
- int num;
-#ifdef WIN32
- __int64 st_size;
-#else
- off_t st_size;
- int mode;
-#endif
-
- struct direntry *file;
- struct tm *tm;
- time_t zero = 0;
-
- for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) {
-
-
- /* Mode */
-#ifdef WIN32
- BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
- BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
- BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
-#else
- mode = file->s.st_mode;
-
- BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
- BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
- BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
-
- if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l';
-
- if (mode & (S_ISUID | S_ISGID)) {
- if (file->mode1[2] == 'x') file->mode1[2] = 's';
- else file->mode1[2] = 'S';
-
- if (file->mode2[2] == 'x') file->mode2[2] = 's';
- }
-
- if (mode & S_ISVTX) {
- if (file->mode3[2] == 'x') file->mode3[2] = 't';
- else file->mode3[2] = 'T';
- }
-#endif
-
-
- /* User */
-#ifdef WIN32
- strcpy(file->owner, "user");
-#else
- {
- struct passwd *pwuser;
- pwuser = getpwuid(file->s.st_uid);
- if (pwuser) {
- BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
- }
- else {
- BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid);
- }
- }
-#endif
-
-
- /* Time */
- tm = localtime(&file->s.st_mtime);
- // prevent impossible dates in windows
- if (tm == NULL) tm = localtime(&zero);
- strftime(file->time, sizeof(file->time), "%H:%M", tm);
- strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
-
-
- /* Size */
- /*
- * Seems st_size is signed 32-bit value in *nix and Windows. This
- * will buy us some time until files get bigger than 4GB or until
- * everyone starts using __USE_FILE_OFFSET64 or equivalent.
- */
- st_size = file->s.st_size;
-
- if (st_size > 1024 * 1024 * 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%.2f GiB", ((double)st_size) / (1024 * 1024 * 1024));
- }
- else if (st_size > 1024 * 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%.1f MiB", ((double)st_size) / (1024 * 1024));
- }
- else if (st_size > 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%d KiB", (int)(st_size / 1024));
- }
- else {
- BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)st_size);
- }
- }
-}
-
-/**
- * Scans the contents of the directory named *dirname, and allocates and fills in an
- * array of entries describing them in *filelist.
- *
- * \return The length of filelist array.
- */
-unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist)
-{
- struct BuildDirCtx dir_ctx;
-
- dir_ctx.nrfiles = 0;
- dir_ctx.files = NULL;
-
- bli_builddir(&dir_ctx, dirname);
- bli_adddirstrings(&dir_ctx);
-
- if (dir_ctx.files) {
- *filelist = dir_ctx.files;
- }
- else {
- // keep blender happy. Blender stores this in a variable
- // where 0 has special meaning.....
- *filelist = MEM_mallocN(sizeof(**filelist), __func__);
- }
-
- return dir_ctx.nrfiles;
-}
-
-/**
- * Deep-duplicate of an array of direntries, including the array itself.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
- */
-void BLI_filelist_duplicate(
- struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
- void *(*dup_poin)(void *))
-{
- unsigned int i;
-
- *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
- for (i = 0; i < nrentries; ++i) {
- struct direntry * const src = &src_filelist[i];
- struct direntry *dest = &(*dest_filelist)[i];
- *dest = *src;
- if (dest->image) {
- dest->image = IMB_dupImBuf(src->image);
- }
- if (dest->relname) {
- dest->relname = MEM_dupallocN(src->relname);
- }
- if (dest->path) {
- dest->path = MEM_dupallocN(src->path);
- }
- if (dest->poin && dup_poin) {
- dest->poin = dup_poin(src->poin);
- }
- }
-}
-
-/**
- * frees storage for an array of direntries, including the array itself.
- */
-void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *))
-{
- unsigned int i;
- for (i = 0; i < nrentries; ++i) {
- struct direntry *entry = filelist + i;
- if (entry->image) {
- IMB_freeImBuf(entry->image);
- }
- if (entry->relname)
- MEM_freeN(entry->relname);
- if (entry->path)
- MEM_freeN(entry->path);
- if (entry->poin && free_poin)
- free_poin(entry->poin);
- }
-
- if (filelist != NULL) {
- MEM_freeN(filelist);
- }
-}
-
/**
* Returns the file size of an opened file descriptor.
@@ -533,6 +227,7 @@ int BLI_exists(const char *name)
#else
struct stat st;
BLI_assert(name);
+ BLI_assert(!BLI_path_is_rel(name));
if (stat(name, &st)) return(0);
#endif
return(st.st_mode);
@@ -592,7 +287,7 @@ bool BLI_is_file(const char *path)
LinkNode *BLI_file_read_as_lines(const char *name)
{
FILE *fp = BLI_fopen(name, "r");
- LinkNode *lines = NULL;
+ LinkNodePair lines = {NULL, NULL};
char *buf;
size_t size;
@@ -602,6 +297,11 @@ LinkNode *BLI_file_read_as_lines(const char *name)
size = (size_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
+ if (UNLIKELY(size == (size_t)-1)) {
+ fclose(fp);
+ return NULL;
+ }
+
buf = MEM_mallocN(size, "file_as_lines");
if (buf) {
size_t i, last = 0;
@@ -616,7 +316,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
if (i == size || buf[i] == '\n') {
char *line = BLI_strdupn(&buf[last], i - last);
- BLI_linklist_prepend(&lines, line);
+ BLI_linklist_append(&lines, line);
/* faster to build singly-linked list in reverse order */
/* alternatively, could process buffer in reverse order so
* list ends up right way round to start with */
@@ -629,9 +329,7 @@ LinkNode *BLI_file_read_as_lines(const char *name)
fclose(fp);
- /* get them the right way round */
- BLI_linklist_reverse(&lines);
- return lines;
+ return lines.list;
}
/*
@@ -674,4 +372,3 @@ bool BLI_file_older(const char *file1, const char *file2)
#endif
return (st1.st_mtime < st2.st_mtime);
}
-
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index cc5a90dbc39..3177bc659b2 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -231,6 +231,30 @@ size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__rest
}
/**
+ * A version of #BLI_vsnprintf that returns ``strlen(buffer)``
+ */
+size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
+{
+ size_t n;
+
+ BLI_assert(buffer != NULL);
+ BLI_assert(maxncpy > 0);
+ BLI_assert(format != NULL);
+
+ n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
+
+ if (n != -1 && n < maxncpy) {
+ /* pass */
+ }
+ else {
+ n = maxncpy - 1;
+ }
+ buffer[n] = '\0';
+
+ return n;
+}
+
+/**
* Portable replacement for #snprintf
*/
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
@@ -250,6 +274,25 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
}
/**
+ * A version of #BLI_snprintf that returns ``strlen(dst)``
+ */
+size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
+{
+ size_t n;
+ va_list arg;
+
+#ifdef DEBUG_STRSIZE
+ memset(dst, 0xff, sizeof(*dst) * maxncpy);
+#endif
+
+ va_start(arg, format);
+ n = BLI_vsnprintf_rlen(dst, maxncpy, format, arg);
+ va_end(arg);
+
+ return n;
+}
+
+/**
* Print formatted string into a newly #MEM_mallocN'd string
* and return it.
*/
@@ -811,9 +854,9 @@ bool BLI_str_endswith(const char *__restrict str, const char *end)
* \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
-size_t BLI_str_partition(const char *str, const char delim[], char **sep, char **suf)
+size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
{
- return BLI_str_partition_ex(str, delim, sep, suf, false);
+ return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
}
/**
@@ -825,30 +868,52 @@ size_t BLI_str_partition(const char *str, const char delim[], char **sep, char *
* \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
-size_t BLI_str_rpartition(const char *str, const char delim[], char **sep, char **suf)
+size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
{
- return BLI_str_partition_ex(str, delim, sep, suf, true);
+ return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
}
/**
* Find the first char matching one of the chars in \a delim, either from left or right.
*
* \param str The string to search within.
+ * \param end If non-NULL, the right delimiter of the string.
* \param delim The set of delimiters to search for, as unicode values.
* \param sep Return value, set to the first delimiter found (or NULL if none found).
* \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
* \param from_right If %true, search from the right of \a str, else, search from its left.
* \return The length of the prefix (i.e. *sep - str).
*/
-size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, char **suf, const bool from_right)
+size_t BLI_str_partition_ex(
+ const char *str, const char *end, const char delim[], const char **sep, const char **suf, const bool from_right)
{
const char *d;
char *(*func)(const char *str, int c) = from_right ? strrchr : strchr;
+ BLI_assert(end == NULL || end > str);
+
*sep = *suf = NULL;
for (d = delim; *d != '\0'; ++d) {
- char *tmp = func(str, *d);
+ const char *tmp;
+
+ if (end) {
+ if (from_right) {
+ for (tmp = end - 1; (tmp >= str) && (*tmp != *d); tmp--);
+ if (tmp < str) {
+ tmp = NULL;
+ }
+ }
+ else {
+ tmp = func(str, *d);
+ if (tmp >= end) {
+ tmp = NULL;
+ }
+ }
+ }
+ else {
+ tmp = func(str, *d);
+ }
if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) {
*sep = tmp;
@@ -860,7 +925,7 @@ size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, cha
return (size_t)(*sep - str);
}
- return strlen(str);
+ return end ? (size_t)(end - str) : strlen(str);
}
/**
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 67ff532cb6f..96033615cf5 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -329,8 +329,8 @@ size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_
}
/**
- * \param start the string to measure the length.
- * \param maxlen the string length (in bytes)
+ * \param strc: the string to measure the length.
+ * \param maxlen: the string length (in bytes)
* \return the unicode length (not in bytes!)
*/
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
@@ -599,14 +599,14 @@ unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__re
/* was g_unichar_to_utf8 */
/**
* BLI_str_utf8_from_unicode:
- * @c a Unicode character code
- * \param outbuf output buffer, must have at least 6 bytes of space.
+ * \param c: a Unicode character code
+ * \param outbuf: output buffer, must have at least 6 bytes of space.
* If %NULL, the length will be computed and returned
* and nothing will be written to outbuf.
*
* Converts a single character to UTF-8.
*
- * Return value: number of bytes written
+ * \return number of bytes written
**/
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf)
{
@@ -734,28 +734,31 @@ char *BLI_str_prev_char_utf8(const char *p)
}
/* end glib copy */
-size_t BLI_str_partition_utf8(const char *str, const unsigned int delim[], char **sep, char **suf)
+size_t BLI_str_partition_utf8(const char *str, const unsigned int delim[], const char **sep, const char **suf)
{
- return BLI_str_partition_ex_utf8(str, delim, sep, suf, false);
+ return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, false);
}
-size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], char **sep, char **suf)
+size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], const char **sep, const char **suf)
{
- return BLI_str_partition_ex_utf8(str, delim, sep, suf, true);
+ return BLI_str_partition_ex_utf8(str, NULL, delim, sep, suf, true);
}
-size_t BLI_str_partition_ex_utf8(const char *str, const unsigned int delim[], char **sep, char **suf,
- const bool from_right)
+size_t BLI_str_partition_ex_utf8(
+ const char *str, const char *end, const unsigned int delim[], const char **sep, const char **suf, const bool from_right)
{
const unsigned int *d;
- const size_t str_len = strlen(str);
+ const size_t str_len = end ? (size_t)(end - str) : strlen(str);
size_t index;
+ /* Note that here, we assume end points to a valid utf8 char! */
+ BLI_assert(end == NULL || (end >= str && (BLI_str_utf8_as_unicode(end) != BLI_UTF8_ERR)));
+
*suf = (char *)(str + str_len);
for (*sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(str, str + str_len) : str), index = 0;
- *sep != NULL && **sep != '\0';
- *sep = (char *)(from_right ? (char *)BLI_str_find_prev_char_utf8(str, *sep) : str + index))
+ *sep >= str && (!end || *sep < end) && **sep != '\0';
+ *sep = (char *)(from_right ? BLI_str_find_prev_char_utf8(str, *sep) : str + index))
{
const unsigned int c = BLI_str_utf8_as_unicode_and_size(*sep, &index);
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index b6b0f14a4e2..5d1bdd6d978 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -99,8 +99,7 @@ void BLI_system_backtrace(FILE *fp)
/* Windows */
#elif defined(_MSC_VER)
- (void)fp;
-#if defined WIN32
+#ifndef NDEBUG
#define MAXSYMBOL 256
#define SIZE 100
unsigned short i;
@@ -127,11 +126,12 @@ void BLI_system_backtrace(FILE *fp)
MEM_freeN(symbolinfo);
#undef MAXSYMBOL
#undef SIZE
-#endif
-
+#else
+ fprintf(fp, "Crash backtrace not supported on release builds\n");
+#endif /* NDEBUG */
+#else /* _MSC_VER */
/* ------------------ */
/* non msvc/osx/linux */
-#else
(void)fp;
#endif
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index d187a8d1968..08d40a158ca 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -417,6 +417,16 @@ 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! */
@@ -498,16 +508,14 @@ BLI_INLINE bool parallel_range_next_iter_get(
int * __restrict iter, int * __restrict count)
{
bool result = false;
+ BLI_spin_lock(&state->lock);
if (state->iter < state->stop) {
- BLI_spin_lock(&state->lock);
- if (state->iter < state->stop) {
- *count = min_ii(state->chunk_size, state->stop - state->iter);
- *iter = state->iter;
- state->iter += *count;
- result = true;
- }
- BLI_spin_unlock(&state->lock);
+ *count = min_ii(state->chunk_size, state->stop - state->iter);
+ *iter = state->iter;
+ state->iter += *count;
+ result = true;
}
+ BLI_spin_unlock(&state->lock);
return result;
}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index ded2fd7e06d..42f7a744b94 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -122,6 +122,7 @@ static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
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 int num_threads_override = 0;
@@ -198,6 +199,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
}
}
+ BLI_spin_lock(&_malloc_lock);
if (thread_levels == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
@@ -210,6 +212,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
}
thread_levels++;
+ BLI_spin_unlock(&_malloc_lock);
}
/* amount of available threads */
@@ -328,9 +331,11 @@ void BLI_end_threads(ListBase *threadbase)
BLI_freelistN(threadbase);
}
+ BLI_spin_lock(&_malloc_lock);
thread_levels--;
if (thread_levels == 0)
MEM_set_lock_callback(NULL, NULL);
+ BLI_spin_unlock(&_malloc_lock);
}
/* System Information */
@@ -338,33 +343,37 @@ void BLI_end_threads(ListBase *threadbase)
/* how many threads are native on this system? */
int BLI_system_thread_count(void)
{
- int t;
+ static int t = -1;
+
+ if (num_threads_override != 0) {
+ return num_threads_override;
+ }
+ else if (LIKELY(t != -1)) {
+ return t;
+ }
+
+ {
#ifdef WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- t = (int) info.dwNumberOfProcessors;
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ t = (int) info.dwNumberOfProcessors;
#else
# ifdef __APPLE__
- int mib[2];
- size_t len;
-
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
- len = sizeof(t);
- sysctl(mib, 2, &t, &len, NULL, 0);
+ int mib[2];
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(t);
+ sysctl(mib, 2, &t, &len, NULL, 0);
# else
- t = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ t = (int)sysconf(_SC_NPROCESSORS_ONLN);
# endif
#endif
+ }
+
+ CLAMP(t, 1, RE_MAX_THREAD);
- if (num_threads_override > 0)
- return num_threads_override;
-
- if (t > RE_MAX_THREAD)
- return RE_MAX_THREAD;
- if (t < 1)
- return 1;
-
return t;
}
@@ -402,6 +411,8 @@ void BLI_lock_thread(int type)
pthread_mutex_lock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_lock(&_fftw_lock);
+ else if (type == LOCK_VIEW3D)
+ pthread_mutex_lock(&_view3d_lock);
}
void BLI_unlock_thread(int type)
@@ -426,6 +437,8 @@ void BLI_unlock_thread(int type)
pthread_mutex_unlock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_unlock(&_fftw_lock);
+ else if (type == LOCK_VIEW3D)
+ pthread_mutex_unlock(&_view3d_lock);
}
/* Mutex Locks */
@@ -768,6 +781,17 @@ int BLI_thread_queue_size(ThreadQueue *queue)
return size;
}
+bool BLI_thread_queue_is_empty(ThreadQueue *queue)
+{
+ bool is_empty;
+
+ pthread_mutex_lock(&queue->mutex);
+ is_empty = BLI_gsqueue_is_empty(queue->queue);
+ pthread_mutex_unlock(&queue->mutex);
+
+ return is_empty;
+}
+
void BLI_thread_queue_nowait(ThreadQueue *queue)
{
pthread_mutex_lock(&queue->mutex);
@@ -797,10 +821,12 @@ void BLI_begin_threaded_malloc(void)
/* Used for debug only */
/* BLI_assert(thread_levels >= 0); */
+ BLI_spin_lock(&_malloc_lock);
if (thread_levels == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
}
thread_levels++;
+ BLI_spin_unlock(&_malloc_lock);
}
void BLI_end_threaded_malloc(void)
@@ -808,8 +834,10 @@ 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)
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 0c8834008b6..39ffbcd7ebe 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -113,22 +113,22 @@ size_t BLI_timecode_string_from_time(
if (power <= 0) {
/* include "frames" in display */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
}
else if (minutes) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
}
}
else {
/* don't include 'frames' in display */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
}
}
break;
@@ -137,10 +137,10 @@ size_t BLI_timecode_string_from_time(
{
/* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
}
break;
}
@@ -156,10 +156,10 @@ size_t BLI_timecode_string_from_time(
const int s_pad = ms_dp + 3;
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
}
break;
}
@@ -168,10 +168,10 @@ size_t BLI_timecode_string_from_time(
/* only show the original seconds display */
/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
if (power <= 0) {
- rlen = BLI_snprintf(str, maxncpy, "%.*f", 1 - power, time_seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
}
break;
}
@@ -179,7 +179,7 @@ size_t BLI_timecode_string_from_time(
default:
{
/* full SMPTE format */
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
break;
}
}
@@ -196,7 +196,6 @@ size_t BLI_timecode_string_from_time(
* \param power special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds time total time in seconds
- * \param seconds time in seconds.
* \return length of \a str
*
* \note in some cases this is used to print non-seconds values.
@@ -208,10 +207,10 @@ size_t BLI_timecode_string_from_time_simple(
/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
if (power <= 0) {
- rlen = BLI_snprintf(str, maxncpy, "%.*f", 1 - power, time_seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
}
return rlen;
diff --git a/source/blender/blenlib/intern/winstuff_dir.c b/source/blender/blenlib/intern/winstuff_dir.c
index b20da9ce959..bde0734a740 100644
--- a/source/blender/blenlib/intern/winstuff_dir.c
+++ b/source/blender/blenlib/intern/winstuff_dir.c
@@ -44,6 +44,22 @@
#include "BLI_utildefines.h"
#include "utfconv.h"
+#define PATH_SUFFIX "\\*"
+#define PATH_SUFFIX_LEN 2
+
+/* keep local to this file */
+struct __dirstream {
+ HANDLE handle;
+ WIN32_FIND_DATAW data;
+ char path[MAX_PATH + PATH_SUFFIX_LEN];
+ long dd_loc;
+ long dd_size;
+ char dd_buf[4096];
+ void *dd_direct;
+
+ struct dirent direntry;
+};
+
/* Note: MinGW (FREE_WINDOWS) has opendir() and _wopendir(), and only the
* latter accepts a path name of wchar_t type. Rather than messing up with
* extra #ifdef's here and there, Blender's own implementations of opendir()
@@ -54,25 +70,25 @@
DIR *opendir(const char *path)
{
wchar_t *path_16 = alloc_utf16_from_8(path, 0);
+ int path_len;
+ DIR *newd = NULL;
- if (GetFileAttributesW(path_16) & FILE_ATTRIBUTE_DIRECTORY) {
- DIR *newd = MEM_mallocN(sizeof(DIR), "opendir");
-
+ if ((GetFileAttributesW(path_16) & FILE_ATTRIBUTE_DIRECTORY) &&
+ ((path_len = strlen(path)) < (sizeof(newd->path) - PATH_SUFFIX_LEN)))
+ {
+ newd = MEM_mallocN(sizeof(DIR), "opendir");
newd->handle = INVALID_HANDLE_VALUE;
- sprintf(newd->path, "%s\\*", path);
-
+ memcpy(newd->path, path, path_len);
+ memcpy(newd->path + path_len, PATH_SUFFIX, PATH_SUFFIX_LEN + 1);
+
newd->direntry.d_ino = 0;
newd->direntry.d_off = 0;
newd->direntry.d_reclen = 0;
newd->direntry.d_name = NULL;
-
- free(path_16);
- return newd;
- }
- else {
- free(path_16);
- return NULL;
}
+
+ free(path_16);
+ return newd;
}
static char *BLI_alloc_utf_8_from_16(wchar_t *in16, size_t add)
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 419d8c0f137..6fdcf7065c3 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -42,7 +42,6 @@ struct Main;
struct MemFile;
struct ReportList;
struct Scene;
-struct SpaceFile;
struct UserDef;
struct bContext;
struct BHead;
@@ -120,8 +119,8 @@ BLO_blendfiledata_free(BlendFileData *bfd);
/**
* Open a blendhandle from a file path.
*
- * \param file The file path to open.
- * \param reports Report errors in opening the file (can be NULL).
+ * \param filepath: The file path to open.
+ * \param reports: Report errors in opening the file (can be NULL).
* \return A handle on success, or NULL on failure.
*/
BlendHandle *BLO_blendhandle_from_file(
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index f716b47ea2e..fb96ec75e62 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -47,11 +47,11 @@ typedef struct MemFile {
} MemFile;
/* actually only used writefile.c */
-extern void add_memfilechunk(MemFile *compare, MemFile *current, const char *buf, unsigned int size);
+extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size);
/* exports */
-extern void BLO_free_memfile(MemFile *memfile);
-extern void BLO_merge_memfile(MemFile *first, MemFile *second);
+extern void BLO_memfile_free(MemFile *memfile);
+extern void BLO_memfile_merge(MemFile *first, MemFile *second);
#endif
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index bd002e59fa4..31dfc71ac73 100644
--- a/source/blender/blenloader/SConscript
+++ b/source/blender/blenloader/SConscript
@@ -43,11 +43,14 @@ incs = [
env['BF_ZLIB_INC'],
]
+defs = []
+
+if env['BF_BUILDINFO']:
+ defs.append('WITH_BUILDINFO')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
-defs = []
-
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 95440158277..20ec27a1f4b 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -176,26 +176,38 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to
prv = BLO_library_read_struct(fd, bhead, "PreviewImage");
if (prv) {
memcpy(new_prv, prv, sizeof(PreviewImage));
- if (prv->rect[0]) {
+ if (prv->rect[0] && prv->w[0] && prv->h[0]) {
unsigned int *rect = NULL;
- new_prv->rect[0] = MEM_callocN(new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int), "prvrect");
+ size_t len = new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int);
+ new_prv->rect[0] = MEM_callocN(len, __func__);
bhead = blo_nextbhead(fd, bhead);
rect = (unsigned int *)(bhead + 1);
- memcpy(new_prv->rect[0], rect, bhead->len);
+ BLI_assert(len == bhead->len);
+ memcpy(new_prv->rect[0], rect, len);
}
else {
+ /* This should not be needed, but can happen in 'broken' .blend files,
+ * better handle this gracefully than crashing. */
+ BLI_assert(prv->rect[0] == NULL && prv->w[0] == 0 && prv->h[0] == 0);
new_prv->rect[0] = NULL;
+ new_prv->w[0] = new_prv->h[0] = 0;
}
- if (prv->rect[1]) {
+ if (prv->rect[1] && prv->w[1] && prv->h[1]) {
unsigned int *rect = NULL;
- new_prv->rect[1] = MEM_callocN(new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int), "prvrect");
+ size_t len = new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int);
+ new_prv->rect[1] = MEM_callocN(len, __func__);
bhead = blo_nextbhead(fd, bhead);
rect = (unsigned int *)(bhead + 1);
- memcpy(new_prv->rect[1], rect, bhead->len);
+ BLI_assert(len == bhead->len);
+ memcpy(new_prv->rect[1], rect, len);
}
else {
+ /* This should not be needed, but can happen in 'broken' .blend files,
+ * better handle this gracefully than crashing. */
+ BLI_assert(prv->rect[1] == NULL && prv->w[1] == 0 && prv->h[1] == 0);
new_prv->rect[1] = NULL;
+ new_prv->w[1] = new_prv->h[1] = 0;
}
MEM_freeN(prv);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6b4d45a85dc..9976594ad0b 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -111,6 +111,7 @@
#include "BLF_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
#include "BKE_cloth.h"
@@ -139,7 +140,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
@@ -1533,9 +1534,16 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
fd->packedmap = oldnewmap_new();
- for (ima = oldmain->image.first; ima; ima = ima->id.next)
+ for (ima = oldmain->image.first; ima; ima = ima->id.next) {
+ ImagePackedFile *imapf;
+
if (ima->packedfile)
insert_packedmap(fd, ima->packedfile);
+
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
+ if (imapf->packedfile)
+ insert_packedmap(fd, imapf->packedfile);
+ }
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
if (vfont->packedfile)
@@ -1568,8 +1576,14 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
entry->newp = NULL;
}
- for (ima = oldmain->image.first; ima; ima = ima->id.next)
+ for (ima = oldmain->image.first; ima; ima = ima->id.next) {
+ ImagePackedFile *imapf;
+
ima->packedfile = newpackedadr(fd, ima->packedfile);
+
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
+ imapf->packedfile = newpackedadr(fd, imapf->packedfile);
+ }
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
vfont->packedfile = newpackedadr(fd, vfont->packedfile);
@@ -1950,7 +1964,6 @@ static void direct_link_palette(FileData *fd, Palette *palette)
{
/* palette itself has been read */
link_list(fd, &palette->colors);
- BLI_listbase_clear(&palette->deleted);
}
static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
@@ -1983,7 +1996,7 @@ static void direct_link_script(FileData *UNUSED(fd), Script *script)
static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
{
PackedFile *pf = newpackedadr(fd, oldpf);
-
+
if (pf) {
pf->data = newpackedadr(fd, pf->data);
}
@@ -2421,12 +2434,13 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
link_list(fd, &adt->nla_tracks);
direct_link_nladata(fd, &adt->nla_tracks);
- /* relink active strip - even though strictly speaking this should only be used
+ /* relink active track/strip - even though strictly speaking this should only be used
* if we're in 'tweaking mode', we need to be able to have this loaded back for
* undo, but also since users may not exit tweakmode before saving (#24535)
*/
// TODO: it's not really nice that anyone should be able to save the file in this
// state, but it's going to be too hard to enforce this single case...
+ adt->act_track = newdataadr(fd, adt->act_track);
adt->actstrip = newdataadr(fd, adt->actstrip);
}
@@ -2628,7 +2642,7 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
* New file versions already have input/output nodes with duplicate links,
* in that case just remove the invalid links.
*/
- int create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
+ const bool create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE) != 0;
float input_locx = 1000000.0f, input_locy = 0.0f;
float output_locx = -1000000.0f, output_locy = 0.0f;
@@ -2749,7 +2763,8 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
ntree->progress = NULL;
ntree->execdata = NULL;
-
+ ntree->duplilock = NULL;
+
ntree->adt = newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);
@@ -2998,7 +3013,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
if (rebuild) {
DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, pose);
}
}
@@ -3392,6 +3407,8 @@ static void lib_link_image(FileData *fd, Main *main)
static void direct_link_image(FileData *fd, Image *ima)
{
+ ImagePackedFile *imapf;
+
/* for undo system, pointers could be restored */
if (fd->imamap)
ima->cache = newimaadr(fd, ima->cache);
@@ -3405,8 +3422,7 @@ static void direct_link_image(FileData *fd, Image *ima)
ima->gputexture = NULL;
ima->rr = NULL;
}
-
- ima->anim = NULL;
+
ima->repbind = NULL;
/* undo system, try to restore render buffers */
@@ -3420,9 +3436,23 @@ static void direct_link_image(FileData *fd, Image *ima)
memset(ima->renders, 0, sizeof(ima->renders));
ima->last_render_slot = ima->render_slot;
}
-
- ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+
+ link_list(fd, &(ima->views));
+ link_list(fd, &(ima->packedfiles));
+
+ if (ima->packedfiles.first) {
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ imapf->packedfile = direct_link_packedfile(fd, imapf->packedfile);
+ }
+ ima->packedfile = NULL;
+ }
+ else {
+ ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+ }
+
+ BLI_listbase_clear(&ima->anims);
ima->preview = direct_link_preview_image(fd, ima->preview);
+ ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format);
ima->ok = 1;
}
@@ -3511,7 +3541,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
nu->bp = newdataadr(fd, nu->bp);
nu->knotsu = newdataadr(fd, nu->knotsu);
nu->knotsv = newdataadr(fd, nu->knotsv);
- if (cu->vfont == NULL) nu->charidx= nu->mat_nr;
+ if (cu->vfont == NULL) nu->charidx = 0;
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
switch_endian_knots(nu);
@@ -4950,6 +4980,20 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
lmd->cache_system = NULL;
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData*)md;
+
+ if (csmd->bind_coords) {
+ csmd->bind_coords = newdataadr(fd, csmd->bind_coords);
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ BLI_endian_switch_float_array((float *)csmd->bind_coords, csmd->bind_coords_num * 3);
+ }
+ }
+
+ /* runtime only */
+ csmd->delta_cache = NULL;
+ csmd->delta_cache_num = 0;
+ }
}
}
@@ -5334,7 +5378,7 @@ static void lib_link_scene(FileData *fd, Main *main)
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
if (seq->scene) {
- seq->scene_sound = sound_scene_add_scene_sound_defaults(sce, seq);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce, seq);
}
}
if (seq->clip) {
@@ -5362,10 +5406,10 @@ static void lib_link_scene(FileData *fd, Main *main)
}
if (seq->sound) {
seq->sound->id.us++;
- seq->scene_sound = sound_add_scene_sound_defaults(sce, seq);
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq);
}
}
- seq->anim = NULL;
+ BLI_listbase_clear(&seq->anims);
lib_link_sequence_modifiers(fd, sce, &seq->modifiers);
}
@@ -5531,13 +5575,14 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SceneRenderLayer *srl;
sce->theDag = NULL;
+ sce->depsgraph = NULL;
sce->obedit = NULL;
sce->stats = NULL;
sce->fps_info = NULL;
sce->customdata_mask_modal = 0;
sce->lay_updated = 0;
- sound_create_scene(sce);
+ BKE_sound_create_scene(sce);
/* set users to one by default, not in lib-link, this will increase it for compo nodes */
sce->id.us = 1;
@@ -5597,6 +5642,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (seq->seq3 == NULL) seq->seq3 = seq->seq2;
seq->effectdata = newdataadr(fd, seq->effectdata);
+ seq->stereo3d_format = newdataadr(fd, seq->stereo3d_format);
if (seq->type & SEQ_TYPE_EFFECT)
seq->flag |= SEQ_EFFECT_NOT_LOADED;
@@ -5605,7 +5651,10 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SpeedControlVars *s = seq->effectdata;
s->frameMap = NULL;
}
-
+
+ seq->prop = newdataadr(fd, seq->prop);
+ IDP_DirectLinkGroup_OrFree(&seq->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
seq->strip = newdataadr(fd, seq->strip);
if (seq->strip && seq->strip->done==0) {
seq->strip->done = true;
@@ -5706,6 +5755,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
link_list(fd, &(sce->markers));
link_list(fd, &(sce->transform_spaces));
link_list(fd, &(sce->r.layers));
+ link_list(fd, &(sce->r.views));
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
@@ -5769,8 +5819,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
BLI_listbase_clear(&win->modalhandlers);
BLI_listbase_clear(&win->subwindows);
BLI_listbase_clear(&win->gesture);
+ BLI_listbase_clear(&win->drawdata);
- win->drawdata = NULL;
win->drawmethod = -1;
win->drawfail = 0;
win->active = 0;
@@ -5778,6 +5828,13 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->cursor = 0;
win->lastcursor = 0;
win->modalcursor = 0;
+ win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
+
+ /* multiview always fallback to anaglyph at file opening
+ * otherwise quadbuffer saved files can break Blender */
+ if (win->stereo3d_format) {
+ win->stereo3d_format->display_mode = S3D_DISPLAY_ANAGLYPH;
+ }
}
BLI_listbase_clear(&wm->timers);
@@ -5928,6 +5985,9 @@ static void lib_link_screen(FileData *fd, Main *main)
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;
+ }
}
else if (sl->spacetype == SPACE_FILE) {
;
@@ -6001,7 +6061,7 @@ static void lib_link_screen(FileData *fd, Main *main)
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
- BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
+ so->storeflag |= SO_TREESTORE_REBUILD;
}
}
}
@@ -6257,6 +6317,9 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
/* TODO: restore path pointers: T40046
* (complicated because this contains data pointers too, not just ID)*/
@@ -6352,7 +6415,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
- BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
+ so->storeflag |= SO_TREESTORE_REBUILD;
}
}
}
@@ -6964,7 +7027,7 @@ static void lib_link_sound(FileData *fd, Main *main)
sound->id.flag -= LIB_NEED_LINK;
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
- sound_load(main, sound);
+ BKE_sound_load(main, sound);
}
}
}
@@ -7034,7 +7097,7 @@ static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_ba
int i;
plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks);
-
+ test_pointer_array(fd, (void**)&plane_track->point_tracks);
for (i = 0; i < plane_track->point_tracksnr; i++) {
plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]);
}
@@ -7749,7 +7812,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.jump_height = 0.4f; /* m */
user->walk_navigation.teleport_time = 0.2f; /* s */
}
-
}
static void do_versions(FileData *fd, Library *lib, Main *main)
@@ -7759,12 +7821,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if (G.debug & G_DEBUG) {
char build_commit_datetime[32];
time_t temp_time = main->build_commit_timestamp;
- struct tm *tm = gmtime(&temp_time);
+ struct tm *tm = (temp_time) ? gmtime(&temp_time) : NULL;
if (LIKELY(tm)) {
strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
}
else {
- BLI_strncpy(build_commit_datetime, "date-unknown", sizeof(build_commit_datetime));
+ BLI_strncpy(build_commit_datetime, "unknown", sizeof(build_commit_datetime));
}
printf("read file %s\n Version %d sub %d date %s hash %s\n",
@@ -7872,7 +7934,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
link_list(fd, &user->user_keymaps);
link_list(fd, &user->addons);
link_list(fd, &user->autoexec_paths);
-
+
for (keymap=user->user_keymaps.first; keymap; keymap=keymap->next) {
keymap->modal_items= NULL;
keymap->poll = NULL;
@@ -9195,7 +9257,6 @@ static void give_base_to_groups(Main *mainvar, Scene *scene)
/* assign the group */
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
- rename_id(&ob->id, group->id.name + 2);
copy_v3_v3(ob->loc, scene->cursor);
}
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 51a68926455..ed22daef9ec 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -38,12 +38,10 @@
struct OldNewMap;
struct MemFile;
-struct bheadsort;
struct ReportList;
struct Object;
struct PartEff;
struct View3D;
-struct bNodeTree;
struct Key;
typedef struct FileData {
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index f70d889828f..d0dc9a88cc0 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -46,7 +46,7 @@
/* **************** support for memory-write, for undo buffers *************** */
/* not memfile itself */
-void BLO_free_memfile(MemFile *memfile)
+void BLO_memfile_free(MemFile *memfile)
{
MemFileChunk *chunk;
@@ -60,7 +60,7 @@ void BLO_free_memfile(MemFile *memfile)
/* to keep list of memfiles consistent, 'first' is always first in list */
/* result is that 'first' is being freed */
-void BLO_merge_memfile(MemFile *first, MemFile *second)
+void BLO_memfile_merge(MemFile *first, MemFile *second)
{
MemFileChunk *fc, *sc;
@@ -77,7 +77,7 @@ void BLO_merge_memfile(MemFile *first, MemFile *second)
if (sc) sc = sc->next;
}
- BLO_free_memfile(first);
+ BLO_memfile_free(first);
}
static int my_memcmp(const int *mem1, const int *mem2, const int len)
@@ -94,7 +94,7 @@ static int my_memcmp(const int *mem1, const int *mem2, const int len)
return 0;
}
-void add_memfilechunk(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
+void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
{
static MemFileChunk *compchunk = NULL;
MemFileChunk *curchunk;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 4125451ead9..2727f3a3965 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -766,7 +766,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
bSoundActuator *sAct = (bSoundActuator*) act->data;
if (sAct->sound) {
sound = blo_do_versions_newlibadr(fd, lib, sAct->sound);
- sAct->flag = sound->flags & SOUND_FLAGS_3D ? ACT_SND_3D_SOUND : 0;
+ sAct->flag = (sound->flags & SOUND_FLAGS_3D) ? ACT_SND_3D_SOUND : 0;
sAct->pitch = sound->pitch;
sAct->volume = sound->volume;
sAct->sound3D.reference_distance = sound->distance;
@@ -795,15 +795,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
char str[FILE_MAX];
BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(str, main->name);
- seq->sound = sound_new_file(main, str);
+ seq->sound = BKE_sound_new_file(main, str);
}
+#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
+#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
/* don't know, if anybody used that this way, but just in case, upgrade to new way... */
if ((seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) &&
!(seq->flag & SEQ_USE_PROXY_CUSTOM_DIR))
{
BLI_snprintf(seq->strip->proxy->dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir);
}
- }
+#undef SEQ_USE_PROXY_CUSTOM_DIR
+#undef SEQ_USE_PROXY_CUSTOM_FILE
+ }
SEQ_END
}
}
@@ -1648,8 +1652,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* brush texture changes */
for (brush = main->brush.first; brush; brush = brush->id.next) {
- default_mtex(&brush->mtex);
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
}
for (ma = main->mat.first; ma; ma = ma->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 10526a191d2..72a320281fe 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -845,7 +845,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
Object *ob;
for (ob = main->object.first; ob; ob = ob->id.next) {
if (is_zero_v3(ob->dscale)) {
- fill_vn_fl(ob->dscale, 3, 1.0f);
+ copy_vn_fl(ob->dscale, 3, 1.0f);
}
}
}
@@ -2096,7 +2096,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (!MAIN_VERSION_ATLEAST(main, 266, 4)) {
Brush *brush;
for (brush = main->brush.first; brush; brush = brush->id.next) {
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) {
brush->spacing /= 2;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index ab5c8ace430..6ab655e9b45 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -39,6 +39,7 @@
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
#include "DNA_sdna_types.h"
+#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -47,12 +48,15 @@
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_actuator_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_genfile.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_sequencer.h"
#include "BKE_screen.h"
#include "BLI_math.h"
@@ -458,10 +462,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
br->mtex.random_angle = 2.0 * M_PI;
br->mask_mtex.random_angle = 2.0 * M_PI;
}
+ }
#undef BRUSH_RAKE
#undef BRUSH_RANDOM_ROTATION
- }
/* Customizable Safe Areas */
if (!MAIN_VERSION_ATLEAST(main, 273, 2)) {
@@ -616,18 +620,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
-
- if (!DNA_struct_elem_find(fd->filesdna, "bSteeringActuator", "float", "acceleration")) {
- for (ob = main->object.first; ob; ob = ob->id.next) {
- bActuator *act;
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_STEERING) {
- bSteeringActuator *sact = act->data;
- sact->acceleration = 1000.f;
- }
- }
- }
- }
}
if (!MAIN_VERSION_ATLEAST(main, 273, 9)) {
@@ -655,4 +647,199 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ if (!MAIN_VERSION_ATLEAST(main, 274, 1)) {
+ /* particle systems need to be forced to redistribute for jitter mode fix */
+ {
+ Object *ob;
+ ParticleSystem *psys;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ }
+ }
+ }
+
+ /* hysteresis setted to 10% but not actived */
+ if (!DNA_struct_elem_find(fd->filesdna, "LodLevel", "int", "obhysteresis")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ LodLevel *level;
+ for (level = ob->lodlevels.first; level; level = level->next) {
+ level->obhysteresis = 10;
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "GameData", "int", "scehysteresis")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ scene->gm.scehysteresis = 10;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 2)) {
+ FOREACH_NODETREE(main, ntree, id) {
+ bNode *node;
+ bNodeSocket *sock;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATERIAL) {
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Refl")) {
+ BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
+ }
+ }
+ }
+ else if (node->type == SH_NODE_MATERIAL_EXT) {
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Refl")) {
+ BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
+ }
+ else if (STREQ(sock->name, "Ray Mirror")) {
+ BLI_strncpy(sock->name, "Reflectivity", sizeof(sock->name));
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 4)) {
+ SceneRenderView *srv;
+ wmWindowManager *wm;
+ bScreen *screen;
+ wmWindow *win;
+ Scene *scene;
+ Camera *cam;
+ Image *ima;
+
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ Sequence *seq;
+
+ BKE_scene_add_render_view(scene, STEREO_LEFT_NAME);
+ srv = scene->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(scene, STEREO_RIGHT_NAME);
+ srv = scene->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
+ SEQ_BEGIN (scene->ed, seq)
+ {
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
+
+#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
+#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
+ if (seq->strip && seq->strip->proxy && !seq->strip->proxy->storage) {
+ if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR)
+ seq->strip->proxy->storage = SEQ_STORAGE_PROXY_CUSTOM_DIR;
+ if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE)
+ seq->strip->proxy->storage = SEQ_STORAGE_PROXY_CUSTOM_FILE;
+ }
+#undef SEQ_USE_PROXY_CUSTOM_DIR
+#undef SEQ_USE_PROXY_CUSTOM_FILE
+
+ }
+ SEQ_END
+ }
+
+ for (screen = main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D *)sl;
+ v3d->stereo3d_camera = STEREO_3D_ID;
+ v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
+ v3d->stereo3d_convergence_alpha = 0.15f;
+ v3d->stereo3d_volume_alpha = 0.05f;
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *) sl;
+ sima->iuser.flag |= IMA_SHOW_STEREO;
+ sima->iuser.passtype = SCE_PASS_COMBINED;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (cam = main->camera.first; cam; cam = cam->id.next) {
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.0f * 0.065f;
+ }
+
+ for (ima = main->image.first; ima; ima = ima->id.next) {
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo 3d Format");
+
+ if (ima->packedfile) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed File");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = ima->packedfile;
+ BLI_strncpy(imapf->filepath, ima->name, FILE_MAX);
+ ima->packedfile = NULL;
+ }
+ }
+
+ for (wm = main->wm.first; wm; wm = wm->id.next) {
+ for (win = wm->windows.first; win; win = win->next) {
+ win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 6)) {
+ bScreen *screen;
+
+ if (!DNA_struct_elem_find(fd->filesdna, "FileSelectParams", "int", "thumbnail_size")) {
+ for (screen = main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+
+ if (sfile->params) {
+ sfile->params->thumbnail_size = 128;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "short", "simplify_subsurf_render")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ scene->r.simplify_subsurf_render = scene->r.simplify_subsurf;
+ scene->r.simplify_particles_render = scene->r.simplify_particles;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "DecimateModifierData", "float", "defgrp_factor")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Decimate) {
+ DecimateModifierData *dmd = (DecimateModifierData *)md;
+ dmd->defgrp_factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 4c7b011097b..0e8e6e9d144 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -92,6 +92,9 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->detail_size = 12;
}
}
+
+ scene->gm.lodflag |= SCE_LOD_USE_HYST;
+ scene->gm.scehysteresis = 10;
}
for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
@@ -118,9 +121,16 @@ void BLO_update_defaults_startup_blend(Main *bmain)
}
}
- /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
for (ar = area->regionbase.first; ar; ar = ar->next) {
+ /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
BLI_freelistN(&ar->panels);
+
+ /* simple fix for 3d view properties scrollbar being not set to top */
+ if (ar->regiontype == RGN_TYPE_UI) {
+ float offset = ar->v2d.tot.ymax - ar->v2d.cur.ymax;
+ ar->v2d.cur.ymax += offset;
+ ar->v2d.cur.ymin += offset;
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 5dae6fbc464..1819dcd4d43 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -77,6 +77,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
@@ -795,22 +796,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
nr = me->totface;
tface = me->tface;
while (nr--) {
- cp = (char *)&tface->col[0];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[1];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[2];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[3];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
+ int j;
+ for (j = 0; j < 4; j++) {
+ int k;
+ cp = ((char *)&tface->col[j]) + 1;
+ for (k = 0; k < 3; k++) {
+ cp[k] = (cp[k] > 126) ? 255 : cp[k] * 2;
+ }
+ }
tface++;
}
@@ -1299,7 +1292,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
Object *ob;
for (vf = main->vfont.first; vf; vf = vf->id.next) {
- if (STREQ(vf->name + strlen(vf->name)-6, ".Bfont")) {
+ if (STREQ(vf->name + strlen(vf->name) - 6, ".Bfont")) {
strcpy(vf->name, FO_BUILTIN_NAME);
}
}
@@ -1958,7 +1951,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* btw. armature_rebuild_pose is further only called on leave editmode */
if (ob->type == OB_ARMATURE) {
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(main, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
@@ -2082,7 +2075,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
data->rootbone = -1;
/* update_pose_etc handles rootbone == -1 */
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(main, ob->pose);
}
}
}
@@ -2487,7 +2480,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
for (group = main->group.first; group; group = group->id.next)
if (group->layer == 0)
- group->layer = (1<<20)-1;
+ group->layer = (1 << 20) - 1;
/* now, subversion control! */
if (main->subversionfile < 3) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 1156d3f30f0..f5954ab75a7 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -333,7 +333,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
/* memory based save */
if (wd->current) {
- add_memfilechunk(NULL, wd->current, mem, memlen);
+ memfile_chunk_add(NULL, wd->current, mem, memlen);
}
else {
if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
@@ -407,7 +407,7 @@ static void mywrite(WriteData *wd, const void *adr, int len)
/**
* BeGiN initializer for mywrite
- * \param file File descriptor
+ * \param ww: File write wrapper.
* \param compare Previous memory file (can be NULL).
* \param current The current memory file (can be NULL).
* \warning Talks to other functions with global parameters
@@ -421,7 +421,7 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
wd->compare= compare;
wd->current= current;
/* this inits comparing */
- add_memfilechunk(compare, NULL, NULL, 0);
+ memfile_chunk_add(compare, NULL, NULL, 0);
return wd;
}
@@ -597,7 +597,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
/* Modifiers */
for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* Write the specific data */
if (fmi && fcm->data) {
@@ -1096,7 +1096,7 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
for (i=0; i<BPHYS_TOT_DATA; i++) {
if (pm->data[i] && pm->data_types & (1<<i)) {
- if (ptcache_data_struct[i][0]=='\0')
+ if (ptcache_data_struct[i][0] == '\0')
writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
else
writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
@@ -1104,7 +1104,7 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
}
for (; extra; extra=extra->next) {
- if (ptcache_extra_struct[extra->type][0]=='\0')
+ if (ptcache_extra_struct[extra->type][0] == '\0')
continue;
writestruct(wd, DATA, "PTCacheExtra", 1, extra);
writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
@@ -1404,7 +1404,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
bConstraint *con;
for (con=conlist->first; con; con=con->next) {
- bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
/* Write the specific data */
if (cti && con->data) {
@@ -1500,7 +1500,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (modbase == NULL) return;
for (md=modbase->first; md; md= md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti == NULL) return;
writestruct(wd, DATA, mti->structName, 1, md);
@@ -1620,6 +1620,13 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ if (csmd->bind_coords) {
+ writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
+ }
+ }
}
}
@@ -1896,26 +1903,35 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count)
{
- CustomData data_tmp;
int i;
- /* This copy will automatically ignore/remove layers set as NO_COPY (and TEMPORARY). */
- CustomData_copy(data, &data_tmp, CD_MASK_EVERYTHING, CD_REFERENCE, count);
+ int nofree_buff[128];
+ int *nofree;
/* write external customdata (not for undo) */
- if (data_tmp.external && !wd->current)
- CustomData_external_write(&data_tmp, id, CD_MASK_MESH, count, 0);
+ if (data->external && !wd->current)
+ CustomData_external_write(data, id, CD_MASK_MESH, count, 0);
+
+ if (data->totlayer > ARRAY_SIZE(nofree_buff)) {
+ nofree = MEM_mallocN(sizeof(*nofree) * (size_t)data->totlayer, __func__);
+ }
+ else {
+ nofree = nofree_buff;
+ }
- for (i = 0; i < data_tmp.totlayer; i++)
- data_tmp.layers[i].flag &= ~CD_FLAG_NOFREE;
+ for (i = 0; i < data->totlayer; i++) {
+ nofree[i] = (data->layers[i].flag & CD_FLAG_NOFREE);
+ data->layers[i].flag &= ~CD_FLAG_NOFREE;
+ }
- writestruct_at_address(wd, DATA, "CustomDataLayer", data_tmp.maxlayer, data->layers, data_tmp.layers);
+ writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers);
- for (i = 0; i < data_tmp.totlayer; i++)
- data_tmp.layers[i].flag |= CD_FLAG_NOFREE;
+ for (i = 0; i < data->totlayer; i++) {
+ data->layers[i].flag |= nofree[i];
+ }
- for (i = 0; i < data_tmp.totlayer; i++) {
- CustomDataLayer *layer= &data_tmp.layers[i];
+ for (i = 0; i < data->totlayer; i++) {
+ CustomDataLayer *layer= &data->layers[i];
const char *structname;
int structnum, datasize;
@@ -1951,10 +1967,12 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
}
}
- if (data_tmp.external)
- writestruct_at_address(wd, DATA, "CustomDataExternal", 1, data->external, data_tmp.external);
+ if (data->external)
+ writestruct(wd, DATA, "CustomDataExternal", 1, data->external);
- CustomData_free(&data_tmp, count);
+ if (nofree != nofree_buff) {
+ MEM_freeN(nofree);
+ }
}
static void write_meshes(WriteData *wd, ListBase *idbase)
@@ -1971,23 +1989,32 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
if (mesh->id.us>0 || wd->current) {
/* write LibData */
if (!save_for_old_blender) {
-
-#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
/* 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));
+#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
+
+ /* Bummer! We need to do the copy *before* writing mesh's struct itself,
+ * because we eliminate NO_COPY & TEMPORARY layers here, which means
+ * **number of layers (data.totlayer) may be smaller!**
+ * If we do not do that, we can get crash by buffer-overflow on reading, see T44461. */
+ CustomData_copy(&old_mesh->vdata, &mesh->vdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totvert);
+ CustomData_copy(&old_mesh->edata, &mesh->edata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totedge);
+#ifndef USE_BMESH_SAVE_WITHOUT_MFACE /* Do not copy org fdata in this case!!! */
+ CustomData_copy(&old_mesh->fdata, &mesh->fdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totface);
+#endif
+ CustomData_copy(&old_mesh->ldata, &mesh->ldata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totloop);
+ CustomData_copy(&old_mesh->pdata, &mesh->pdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totpoly);
writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
-#else
- writestruct(wd, ID_ME, "Mesh", 1, mesh);
-#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
/* direct data */
if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
@@ -2003,11 +2030,16 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
-#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
+#ifndef USE_BMESH_SAVE_WITHOUT_MFACE
+ CustomData_free(&mesh->fdata, mesh->totface);
+#endif
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+
/* restore pointer */
mesh = old_mesh;
-#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
-
}
else {
@@ -2034,6 +2066,10 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
BKE_mesh_update_customdata_pointers(mesh, false);
+ /* See comment above. Note that loop/poly data are ignored here, and face ones are already handled. */
+ CustomData_copy(&old_mesh->vdata, &mesh->vdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totvert);
+ CustomData_copy(&old_mesh->edata, &mesh->edata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totedge);
+
writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
/* direct data */
@@ -2052,6 +2088,8 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
#endif
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
CustomData_free(&mesh->fdata, mesh->totface);
/* restore pointer */
@@ -2117,22 +2155,39 @@ static void write_images(WriteData *wd, ListBase *idbase)
{
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);
if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
- if (ima->packedfile) {
- pf = ima->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
+ 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);
+ }
}
write_previews(wd, ima->preview);
+
+ for (iv = ima->views.first; iv; iv = iv->next)
+ writestruct(wd, DATA, "ImageView", 1, iv);
+ writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format);
+
+ ima->packedfile = NULL;
}
ima= ima->id.next;
}
@@ -2287,7 +2342,7 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
SequenceModifierData *smd;
for (smd = modbase->first; smd; smd = smd->next) {
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti) {
writestruct(wd, DATA, smti->struct_name, 1, smd);
@@ -2333,6 +2388,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
TimeMarker *marker;
TransformOrientation *ts;
SceneRenderLayer *srl;
+ SceneRenderView *srv;
ToolSettings *tos;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
@@ -2414,7 +2470,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
break;
}
}
-
+
+ writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format);
+
strip= seq->strip;
writestruct(wd, DATA, "Strip", 1, strip);
if (seq->flag & SEQ_USE_CROP && strip->crop) {
@@ -2434,6 +2492,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
strip->done = true;
}
+ if (seq->prop) {
+ IDP_WriteProperty(seq->prop, wd);
+ }
+
write_sequence_modifiers(wd, &seq->modifiers);
}
SEQ_END
@@ -2475,6 +2537,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
}
}
+
+ /* writing MultiView to the blend file */
+ for (srv = sce->r.views.first; srv; srv = srv->next)
+ writestruct(wd, DATA, "SceneRenderView", 1, srv);
if (sce->nodetree) {
writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
@@ -2537,8 +2603,10 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb)
for (wm= lb->first; wm; wm= wm->id.next) {
writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
- for (win= wm->windows.first; win; win= win->next)
+ for (win= wm->windows.first; win; win= win->next) {
writestruct(wd, DATA, "wmWindow", 1, win);
+ writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format);
+ }
}
}
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 80adb595ac9..66ee184a5bc 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -61,6 +61,8 @@ set(SRC
operators/bmo_mesh_conv.c
operators/bmo_mirror.c
operators/bmo_normals.c
+ operators/bmo_offset_edgeloops.c
+ operators/bmo_planar_faces.c
operators/bmo_poke.c
operators/bmo_primitive.c
operators/bmo_removedoubles.c
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 120ff4997dc..ada0fabd28e 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -256,11 +256,28 @@ enum {
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
+/* args for _Generic */
+#define _BM_GENERIC_TYPE_ELEM_NONCONST \
+ void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
+ BMElem *, BMElemF *, BMHeader *
+
+#define _BM_GENERIC_TYPE_ELEM_CONST \
+ const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \
+ const BMElem *, const BMElemF *, const BMHeader *, \
+ void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \
+ BMElem * const, BMElemF * const, BMHeader * const
+
+#define BM_CHECK_TYPE_ELEM_CONST(ele) \
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPES_CONST)
+
+#define BM_CHECK_TYPE_ELEM_NONCONST(ele) \
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+
#define BM_CHECK_TYPE_ELEM(ele) \
- CHECK_TYPE_ANY(ele, void *, BMFace *, BMEdge *, BMVert *, BMLoop *, BMElem *, BMElemF *, BMHeader *)
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST)
#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
- (BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), ele
+ (BM_CHECK_TYPE_ELEM(ele)), ele
/* BMHeader->hflag (char) */
enum {
@@ -297,8 +314,17 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
#define BM_ELEM_CD_GET_INT(ele, offset) \
(assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset))))
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define BM_ELEM_CD_GET_VOID_P(ele, offset) \
+ (assert(offset != -1), \
+ _Generic(ele, \
+ GENERIC_TYPE_ANY( POINTER_OFFSET((ele)->head.data, offset), _BM_GENERIC_TYPE_ELEM_NONCONST), \
+ GENERIC_TYPE_ANY((const void *)POINTER_OFFSET((ele)->head.data, offset), _BM_GENERIC_TYPE_ELEM_CONST)) \
+ )
+#else
#define BM_ELEM_CD_GET_VOID_P(ele, offset) \
(assert(offset != -1), (void *)((char *)(ele)->head.data + (offset)))
+#endif
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \
assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index e0348fea636..7664108f348 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -46,9 +46,41 @@
#define SELECT 1
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ *
+ * \returns false if any edges aren't found .
+ */
+bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
+{
+ int i, i_prev = len - 1;
+ for (i = 0; i < len; i++) {
+ edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
+ if (edge_arr[i_prev] == NULL) {
+ return false;
+ }
+ i_prev = i;
+ }
+ return true;
+}
+
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ * Creating edges as-needed.
+ */
+void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
+{
+ int i, i_prev = len - 1;
+ for (i = 0; i < len; i++) {
+ edge_arr[i_prev] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE);
+ i_prev = i;
+ }
+}
+
/* prototypes */
-static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMLoop *source_loop, BMLoop *target_loop);
+static void bm_loop_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop);
/**
* \brief Make Quad/Triangle
@@ -64,9 +96,10 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
* of the vertices in the vertex array.
*/
-BMFace *BM_face_create_quad_tri(BMesh *bm,
- BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+BMFace *BM_face_create_quad_tri(
+ BMesh *bm,
+ BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
BMVert *vtar[4] = {v1, v2, v3, v4};
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
@@ -81,8 +114,9 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
* this is done since the face may not be completely surrounded by faces,
* this way: a quad with 2 connected quads on either side will still get all 4 loops updated
*/
-void BM_face_copy_shared(BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data)
+void BM_face_copy_shared(
+ BMesh *bm, BMFace *f,
+ BMElemFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
BMLoop *l_iter;
@@ -132,155 +166,113 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f,
}
/**
- * \brief Make NGon
+ * Given an array of edges,
+ * order them using the winding defined by \a v1 & \a v2
+ * into \a edges_sort & \a verts_sort.
*
- * Makes an ngon from an unordered list of edges. \a v1 and \a v2
- * must be the verts defining edges[0],
- * and define the winding of the new face.
- *
- * \a edges are not required to be ordered, simply to to form
- * a single closed loop as a whole.
- *
- * \note While this function will work fine when the edges
- * are already sorted, if the edges are always going to be sorted,
- * #BM_face_create should be considered over this function as it
- * avoids some unnecessary work.
+ * All arrays must be \a len long.
*/
-BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+static bool bm_edges_sort_winding(
+ BMVert *v1, BMVert *v2,
+ BMEdge **edges, const int len,
+ BMEdge **edges_sort, BMVert **verts_sort)
{
- BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
- BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1);
- int esort_index = 0;
- int vsort_index = 0;
-
- BMFace *f = NULL;
- BMEdge *e;
- BMVert *v, *ev1, *ev2;
+ BMEdge *e_iter, *e_first;
+ BMVert *v_iter;
int i;
- bool is_v1_found, is_reverse;
-
- /* this code is hideous, yeek. I'll have to think about ways of
- * cleaning it up. basically, it now combines the old BM_face_create_ngon
- * _and_ the old bmesh_mf functions, so its kindof smashed together
- * - joeedh */
-
- BLI_assert(len && v1 && v2 && edges && bm);
-
- /* put edges in correct order */
+ /* all flags _must_ be cleared on exit! */
for (i = 0; i < len; i++) {
BM_ELEM_API_FLAG_ENABLE(edges[i], _FLAG_MF);
+ BM_ELEM_API_FLAG_ENABLE(edges[i]->v1, _FLAG_MV);
+ BM_ELEM_API_FLAG_ENABLE(edges[i]->v2, _FLAG_MV);
}
- ev1 = edges[0]->v1;
- ev2 = edges[0]->v2;
-
- BLI_assert(ELEM(v1, ev1, ev2) && ELEM(v2, ev1, ev2));
-
- if (v1 == ev2) {
- /* Swapping here improves performance and consistency of face
- * structure in the special case that the edges are already in
- * the correct order and winding */
- SWAP(BMVert *, ev1, ev2);
- }
-
- verts_sort[vsort_index++] = ev1;
- v = ev2;
- e = edges[0];
+ /* find first edge */
+ i = 0;
+ v_iter = v1;
+ e_iter = e_first = v1->e;
do {
- BMEdge *e2 = e;
-
- /* vertex array is (len + 1) */
- if (UNLIKELY(vsort_index > len)) {
- goto err; /* vertex in loop twice */
+ if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF) &&
+ (BM_edge_other_vert(e_iter, v_iter) == v2))
+ {
+ i = 1;
+ break;
}
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
+ if (i == 0) {
+ goto error;
+ }
- verts_sort[vsort_index++] = v;
- edges_sort[esort_index++] = e;
-
- /* we only flag the verts to check if they are in the face more than once */
- BM_ELEM_API_FLAG_ENABLE(v, _FLAG_MV);
-
- do {
- e2 = bmesh_disk_edge_next(e2, v);
- if (e2 != e && BM_ELEM_API_FLAG_TEST(e2, _FLAG_MF)) {
- v = BM_edge_other_vert(e2, v);
- break;
+ i = 0;
+ do {
+ /* entering loop will always succeed */
+ if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF)) {
+ if (UNLIKELY(BM_ELEM_API_FLAG_TEST(v_iter, _FLAG_MV) == false)) {
+ /* vert is in loop multiple times */
+ goto error;
}
- } while (e2 != e);
- if (UNLIKELY(e2 == e)) {
- goto err; /* the edges do not form a closed loop */
- }
+ BM_ELEM_API_FLAG_DISABLE(e_iter, _FLAG_MF);
+ edges_sort[i] = e_iter;
- e = e2;
- } while (e != edges[0]);
+ BM_ELEM_API_FLAG_DISABLE(v_iter, _FLAG_MV);
+ verts_sort[i] = v_iter;
- if (UNLIKELY(esort_index != len)) {
- goto err; /* we didn't use all edges in forming the boundary loop */
- }
+ i += 1;
- /* ok, edges are in correct order, now ensure they are going
- * in the correct direction */
- is_v1_found = is_reverse = false;
- for (i = 0; i < len; i++) {
- if (BM_vert_in_edge(edges_sort[i], v1)) {
- /* see if v1 and v2 are in the same edge */
- if (BM_vert_in_edge(edges_sort[i], v2)) {
- /* if v1 is shared by the *next* edge, then the winding
- * is incorrect */
- if (BM_vert_in_edge(edges_sort[(i + 1) % len], v1)) {
- is_reverse = true;
- break;
+ /* walk onto the next vertex */
+ v_iter = BM_edge_other_vert(e_iter, v_iter);
+ if (i == len) {
+ if (UNLIKELY(v_iter != verts_sort[0])) {
+ goto error;
}
+ break;
}
- is_v1_found = true;
- }
-
- if ((is_v1_found == false) && BM_vert_in_edge(edges_sort[i], v2)) {
- is_reverse = true;
- break;
+ e_first = e_iter;
}
- }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
- if (is_reverse) {
- for (i = 0; i < len / 2; i++) {
- v = verts_sort[i];
- verts_sort[i] = verts_sort[len - i - 1];
- verts_sort[len - i - 1] = v;
- }
+ if (i == len) {
+ return true;
}
+error:
for (i = 0; i < len; i++) {
- edges_sort[i] = BM_edge_exists(verts_sort[i], verts_sort[(i + 1) % len]);
- if (UNLIKELY(edges_sort[i] == NULL)) {
- goto err;
- }
-
- /* check if vert is in face more than once. if the flag is disabled. we've already visited */
- if (UNLIKELY(!BM_ELEM_API_FLAG_TEST(verts_sort[i], _FLAG_MV))) {
- goto err;
- }
- BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV);
+ BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
+ BM_ELEM_API_FLAG_DISABLE(edges[i]->v1, _FLAG_MV);
+ BM_ELEM_API_FLAG_DISABLE(edges[i]->v2, _FLAG_MV);
}
- f = BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
+ return false;
+}
- /* clean up flags */
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(edges_sort[i], _FLAG_MF);
- }
+/**
+ * \brief Make NGon
+ *
+ * Makes an ngon from an unordered list of edges.
+ * Verts \a v1 and \a v2 define the winding of the new face.
+ *
+ * \a edges are not required to be ordered, simply to to form
+ * a single closed loop as a whole.
+ *
+ * \note While this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * #BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
+BMFace *BM_face_create_ngon(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
+{
+ BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
+ BMVert **verts_sort = BLI_array_alloca(verts_sort, len);
- return f;
+ BLI_assert(len && v1 && v2 && edges && bm);
-err:
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
- }
- for (i = 0; i < vsort_index; i++) {
- BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV);
+ if (bm_edges_sort_winding(v1, v2, edges, len, edges_sort, verts_sort)) {
+ return BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
}
return NULL;
@@ -294,9 +286,10 @@ err:
* - Optionally create edges between vertices.
* - Uses verts so no need to find edges (handy when you only have verts)
*/
-BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool calc_winding, const bool create_edges)
+BMFace *BM_face_create_ngon_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool calc_winding, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
unsigned int winding[2] = {0, 0};
@@ -375,8 +368,9 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
*
* \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)
+BMFace *BM_face_create_ngon_vcloud(
+ BMesh *bm, BMVert **vert_arr, int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
@@ -497,8 +491,9 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len,
/*************************************************************/
-static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMVert *source_vertex, BMVert *target_vertex)
+static void bm_vert_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMVert *source_vertex, BMVert *target_vertex)
{
if ((source_mesh == target_mesh) && (source_vertex == target_vertex)) {
BLI_assert(!"BMVert: source and targer match");
@@ -510,8 +505,9 @@ static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_vertex->head.data, &target_vertex->head.data);
}
-static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMEdge *source_edge, BMEdge *target_edge)
+static void bm_edge_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMEdge *source_edge, BMEdge *target_edge)
{
if ((source_mesh == target_mesh) && (source_edge == target_edge)) {
BLI_assert(!"BMEdge: source and targer match");
@@ -522,8 +518,9 @@ static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_edge->head.data, &target_edge->head.data);
}
-static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMLoop *source_loop, BMLoop *target_loop)
+static void bm_loop_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop)
{
if ((source_mesh == target_mesh) && (source_loop == target_loop)) {
BLI_assert(!"BMLoop: source and targer match");
@@ -534,8 +531,9 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_loop->head.data, &target_loop->head.data);
}
-static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMFace *source_face, BMFace *target_face)
+static void bm_face_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMFace *source_face, BMFace *target_face)
{
if ((source_mesh == target_mesh) && (source_face == target_face)) {
BLI_assert(!"BMFace: source and targer match");
@@ -555,8 +553,9 @@ static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
* Copies attributes, e.g. customdata, header flags, etc, from one element
* to another of the same type.
*/
-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)
+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)
{
const BMHeader *ele_src = ele_src_v;
BMHeader *ele_dst = ele_dst_v;
@@ -621,9 +620,10 @@ void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v,
}
/* helper function for 'BM_mesh_copy' */
-static BMFace *bm_mesh_copy_new_face(BMesh *bm_new, BMesh *bm_old,
- BMVert **vtable, BMEdge **etable,
- BMFace *f)
+static BMFace *bm_mesh_copy_new_face(
+ BMesh *bm_new, BMesh *bm_old,
+ BMVert **vtable, BMEdge **etable,
+ BMFace *f)
{
BMLoop **loops = BLI_array_alloca(loops, f->len);
BMVert **verts = BLI_array_alloca(verts, f->len);
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 12d3a4bd474..29503679547 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -29,23 +29,32 @@
struct BMAllocTemplate;
-BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- const BMFace *f_example, const eBMCreateFlag create_flag);
+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);
-void BM_face_copy_shared(BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data);
+BMFace *BM_face_create_quad_tri(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool calc_winding, const bool create_edges);
+void BM_face_copy_shared(
+ BMesh *bm, BMFace *f,
+ BMElemFilterFunc filter_fn, void *user_data);
-BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_ngon(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_ngon_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool calc_winding, const bool create_edges);
-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);
+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);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 9e0807710fc..4c09a35bdd1 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -31,7 +31,7 @@
#include "BLI_math_vector.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
-#include "BLI_smallhash.h"
+#include "BLI_linklist_stack.h"
#include "BLI_stackdefines.h"
#include "BLF_translation.h"
@@ -57,8 +57,9 @@
/**
* \brief Main function for creating a new vertex.
*/
-BMVert *BM_vert_create(BMesh *bm, const float co[3],
- const BMVert *v_example, const eBMCreateFlag create_flag)
+BMVert *BM_vert_create(
+ BMesh *bm, const float co[3],
+ const BMVert *v_example, const eBMCreateFlag create_flag)
{
BMVert *v = BLI_mempool_alloc(bm->vpool);
@@ -88,7 +89,7 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
else {
zero_v3(v->co);
}
- zero_v3(v->no);
+ /* 'v->no' set below */
v->e = NULL;
/* --- done --- */
@@ -107,6 +108,7 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
if (v_example) {
int *keyi;
+ /* handles 'v->no' too */
BM_elem_attrs_copy(bm, bm, v_example, v);
/* exception: don't copy the original shapekey index */
@@ -117,6 +119,15 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
}
else {
CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+ zero_v3(v->no);
+ }
+ }
+ else {
+ if (v_example) {
+ copy_v3_v3(v->no, v_example->no);
+ }
+ else {
+ zero_v3(v->no);
}
}
@@ -131,8 +142,9 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
* \note Duplicate edges are supported by the API however users should _never_ see them.
* so unless you need a unique edge or know the edge won't exist, you should call with \a no_double = true
*/
-BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
- const BMEdge *e_example, const eBMCreateFlag create_flag)
+BMEdge *BM_edge_create(
+ BMesh *bm, BMVert *v1, BMVert *v2,
+ const BMEdge *e_example, const eBMCreateFlag create_flag)
{
BMEdge *e;
@@ -194,8 +206,9 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
return e;
}
-static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
- const BMLoop *l_example, const eBMCreateFlag create_flag)
+static BMLoop *bm_loop_create(
+ BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
+ const BMLoop *l_example, const eBMCreateFlag create_flag)
{
BMLoop *l = NULL;
@@ -213,8 +226,8 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
BM_elem_index_set(l, -1); /* set_ok_invalid */
#endif
- l->head.hflag = 0;
l->head.htype = BM_LOOP;
+ l->head.hflag = 0;
l->head.api_flag = 0;
l->v = v;
@@ -244,8 +257,9 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
return l;
}
-static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte,
- const eBMCreateFlag create_flag)
+static BMLoop *bm_face_boundary_add(
+ BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte,
+ const eBMCreateFlag create_flag)
{
#ifdef USE_BMESH_HOLES
BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
@@ -266,8 +280,9 @@ static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge
return l;
}
-BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f,
- const bool copy_verts, const bool copy_edges)
+BMFace *BM_face_copy(
+ BMesh *bm_dst, BMesh *bm_src, BMFace *f,
+ const bool copy_verts, const bool copy_edges)
{
BMVert **verts = BLI_array_alloca(verts, f->len);
BMEdge **edges = BLI_array_alloca(edges, f->len);
@@ -362,7 +377,8 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
f->l_first = NULL;
#endif
f->len = 0;
- zero_v3(f->no);
+ /* caller must initialize */
+ // zero_v3(f->no);
f->mat_nr = 0;
/* --- done --- */
@@ -389,8 +405,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
* \param len Length of the face
* \param create_flag Options for creating the face
*/
-BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+BMFace *BM_face_create(
+ BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
BMFace *f = NULL;
BMLoop *l, *startl, *lastl;
@@ -443,6 +460,15 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
}
else {
CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+ zero_v3(f->no);
+ }
+ }
+ else {
+ if (f_example) {
+ copy_v3_v3(f->no, f_example->no);
+ }
+ else {
+ zero_v3(f->no);
}
}
@@ -454,25 +480,18 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
/**
* Wrapper for #BM_face_create when you don't have an edge array
*/
-BMFace *BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
+BMFace *BM_face_create_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
- int i, i_prev = len - 1;
if (create_edges) {
- for (i = 0; i < len; i++) {
- edge_arr[i_prev] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE);
- i_prev = i;
- }
+ BM_edges_from_verts_ensure(bm, edge_arr, vert_arr, len);
}
else {
- for (i = 0; i < len; i++) {
- edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
- if (edge_arr[i_prev] == NULL) {
- return NULL;
- }
- i_prev = i;
+ if (BM_edges_from_verts(edge_arr, vert_arr, len) == false) {
+ return NULL;
}
}
@@ -1026,8 +1045,9 @@ static bool disk_is_flagged(BMVert *v, const char api_flag)
return false;
}
- if (bmesh_radial_length(l) == 1)
+ if (BM_edge_is_boundary(l->e)) {
return false;
+ }
do {
if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag))
@@ -1111,7 +1131,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
* else this will remove the face as well - campbell */
- if (BM_edge_face_count(l_iter->e) <= 2) {
+ if (!BM_edge_face_count_is_over(l_iter->e, 3)) {
if (do_del) {
BLI_array_append(deledges, l_iter->e);
}
@@ -1307,14 +1327,14 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
*
* \return A BMFace pointer
*/
-BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
- BMLoop **r_l,
+BMFace *bmesh_sfme(
+ BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
+ BMLoop **r_l,
#ifdef USE_BMESH_HOLES
- ListBase *holes,
+ ListBase *holes,
#endif
- BMEdge *e_example,
- const bool no_double
- )
+ BMEdge *e_example,
+ const bool no_double)
{
#ifdef USE_BMESH_HOLES
BMLoopList *lst, *lst2;
@@ -1481,14 +1501,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
bmesh_disk_edge_remove(e_new, tv);
bmesh_disk_edge_remove(e_new, v_new);
- /* remove e from tv's disk cycle */
- bmesh_disk_edge_remove(e, tv);
-
- /* swap out tv for v_new in e */
- bmesh_edge_swapverts(e, tv, v_new);
-
- /* add e to v_new's disk cycle */
- bmesh_disk_edge_append(e, v_new);
+ bmesh_disk_vert_replace(e, v_new, tv);
/* add e_new to v_new's disk cycle */
bmesh_disk_edge_append(e_new, v_new);
@@ -1653,13 +1666,14 @@ 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(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_double)
+BMEdge *bmesh_jekv(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_double)
{
BMEdge *e_old;
BMVert *v_old, *tv;
BMLoop *l_kill;
- int len, radlen = 0, i;
+ int radlen = 0, i;
bool halt = false;
#ifndef NDEBUG
bool edok;
@@ -1670,10 +1684,8 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
if (BM_vert_in_edge(e_kill, v_kill) == 0) {
return NULL;
}
-
- len = bmesh_disk_count(v_kill);
- if (len == 2) {
+ if (bmesh_disk_count_ex(v_kill, 3) == 2) {
#ifndef NDEBUG
int valence1, valence2;
BMLoop *l;
@@ -1700,12 +1712,8 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
e_splice = BM_edge_exists(tv, v_old);
}
- /* remove e_old from v_kill's disk cycle */
- bmesh_disk_edge_remove(e_old, v_kill);
- /* relink e_old->v_kill to be e_old->tv */
- bmesh_edge_swapverts(e_old, v_kill, tv);
- /* append e_old to tv's disk cycle */
- bmesh_disk_edge_append(e_old, tv);
+ bmesh_disk_vert_replace(e_old, tv, v_kill);
+
/* remove e_kill from tv's disk cycle */
bmesh_disk_edge_remove(e_kill, tv);
@@ -1789,7 +1797,7 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
if (check_edge_double) {
if (e_splice) {
/* removes e_splice */
- BM_edge_splice(bm, e_splice, e_old);
+ BM_edge_splice(bm, e_old, e_splice);
}
}
@@ -1963,27 +1971,38 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
BLI_assert(BM_edge_exists(v_a, v_b) == false);
if (v_a->e && v_b->e) {
- SmallHash visit;
BMEdge *e, *e_first;
- BLI_smallhash_init(&visit);
+#define VERT_VISIT _FLAG_WALK
+ /* tag 'v_a' */
e = e_first = v_a->e;
do {
BMVert *v_other = BM_edge_other_vert(e, v_a);
- BLI_smallhash_insert(&visit, (uintptr_t)v_other, NULL);
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(v_other, VERT_VISIT);
} while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
+ /* check 'v_b' connects to 'v_a' edges */
e = e_first = v_b->e;
do {
BMVert *v_other = BM_edge_other_vert(e, v_b);
- if (BLI_smallhash_haskey(&visit, (uintptr_t)v_other)) {
+ if (BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT)) {
is_double = true;
break;
}
} while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first);
- BLI_smallhash_release(&visit);
+ /* cleanup */
+ e = e_first = v_a->e;
+ do {
+ BMVert *v_other = BM_edge_other_vert(e, v_a);
+ BLI_assert(BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT));
+ BM_ELEM_API_FLAG_DISABLE(v_other, VERT_VISIT);
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
+
+#undef VERT_VISIT
+
}
return is_double;
@@ -1992,7 +2011,8 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
/**
* \brief Splice Vert
*
- * Merges two verts into one (\a v into \a vtarget).
+ * Merges two verts into one
+ * (\a v_src into \a v_dst, removing \a v_src).
*
* \return Success
*
@@ -2000,49 +2020,42 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
* where \a v and \a vtarget are connected by an edge
* (assert checks for this case).
*/
-bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
+bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
{
BMEdge *e;
/* verts already spliced */
- if (v == v_target) {
+ if (v_src == v_dst) {
return false;
}
- BLI_assert(BM_vert_pair_share_face_check(v, v_target) == false);
-
- /* move all the edges from v's disk to vtarget's disk */
- while ((e = v->e)) {
+ BLI_assert(BM_vert_pair_share_face_check(v_src, v_dst) == false);
- /* loop */
- BMLoop *l_first;
- if ((l_first = e->l)) {
- BMLoop *l_iter = l_first;
- do {
- if (l_iter->v == v) {
- l_iter->v = v_target;
- }
- /* else if (l_iter->prev->v == v) {...}
- * (this case will be handled by a different edge) */
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-
- /* disk */
- bmesh_disk_edge_remove(e, v);
- bmesh_edge_swapverts(e, v, v_target);
- bmesh_disk_edge_append(e, v_target);
+ /* move all the edges from 'v_src' disk to 'v_dst' */
+ while ((e = v_src->e)) {
+ bmesh_edge_vert_swap(e, v_dst, v_src);
BLI_assert(e->v1 != e->v2);
}
- BM_CHECK_ELEMENT(v);
- BM_CHECK_ELEMENT(v_target);
+ BM_CHECK_ELEMENT(v_src);
+ BM_CHECK_ELEMENT(v_dst);
- /* v is unused now, and can be killed */
- BM_vert_kill(bm, v);
+ /* 'v_src' is unused now, and can be killed */
+ BM_vert_kill(bm, v_src);
return true;
}
+
+/** \name BM_vert_separate, bmesh_vert_separate and friends
+ * \{ */
+
+/* BM_edge_face_count(e) >= 1 */
+BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
+{
+ return (e->l && e->l->radial_next != e->l);
+}
+
/**
* \brief Separate Vert
*
@@ -2054,167 +2067,252 @@ bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
*
* \return Success
*/
-void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- const bool copy_select)
+void bmesh_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select)
{
- const int v_edgetot = BM_vert_face_count(v);
- BMEdge **stack = BLI_array_alloca(stack, v_edgetot);
- STACK_DECLARE(stack);
+ int v_edges_num = 0;
- SmallHash visithash;
- BMVert **verts = NULL;
- BMIter eiter, liter;
- BMLoop *l;
- BMEdge *e;
- int i, maxindex;
- BMLoop *l_new;
+ /* Detailed notes on array use since this is stack memory, we have to be careful */
- BLI_smallhash_init_ex(&visithash, v_edgetot);
+ /* newly created vertices, only use when 'r_vout' is set
+ * (total size will be number of fans) */
+ BLI_SMALLSTACK_DECLARE(verts_new, BMVert *);
+ /* fill with edges from the face-fan, clearing on completion
+ * (total size will be max fan edge count) */
+ BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+ /* temp store edges to walk over when filling 'edges',
+ * (total size will be max radial edges of any edge) */
+ BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
- STACK_INIT(stack, v_edgetot);
+ /* number of resulting verts, include self */
+ int verts_num = 1;
+ /* track the total number of edges handled, so we know when we've found the last fan */
+ int edges_found = 0;
- maxindex = 0;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BLI_smallhash_haskey(&visithash, (uintptr_t)e)) {
- continue;
- }
+#define EDGE_VISIT _FLAG_WALK
+
+ /* count and flag at once */
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v->e;
+ do {
+ v_edges_num += 1;
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(e_iter, EDGE_VISIT);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ while (true) {
/* Considering only edges and faces incident on vertex v, walk
- * the edges & faces and assign an index to each connected set */
- BLI_smallhash_insert(&visithash, (uintptr_t)e, SET_INT_IN_POINTER(maxindex));
+ * the edges & collect in the 'edges' list for splitting */
+
+ BMEdge *e = v->e;
+ BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT);
+
do {
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT));
+ BLI_SMALLSTACK_PUSH(edges, e);
+ edges_found += 1;
+
if (e->l) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
- l_new = (l_iter->v == v) ? l_iter->prev : l_iter->next;
- BLI_assert(BM_vert_in_edge(l_new->e, v));
- if (!BLI_smallhash_haskey(&visithash, (uintptr_t)l_new->e)) {
- BLI_smallhash_insert(&visithash, (uintptr_t)l_new->e, SET_INT_IN_POINTER(maxindex));
- STACK_PUSH(stack, l_new->e);
+ BMLoop *l_adjacent = (l_iter->v == v) ? l_iter->prev : l_iter->next;
+ BLI_assert(BM_vert_in_edge(l_adjacent->e, v));
+ if (BM_ELEM_API_FLAG_TEST(l_adjacent->e, EDGE_VISIT)) {
+ BM_ELEM_API_FLAG_DISABLE(l_adjacent->e, EDGE_VISIT);
+ BLI_SMALLSTACK_PUSH(edges_search, l_adjacent->e);
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
- } while ((e = STACK_POP(stack)));
+ } while ((e = BLI_SMALLSTACK_POP(edges_search)));
- maxindex++;
- }
-
- /* Make enough verts to split v for each group */
- if (r_vout != NULL) {
- verts = MEM_callocN(sizeof(BMVert *) * maxindex, __func__);
- }
- else {
- verts = BLI_array_alloca(verts, maxindex);
- }
+ /* now we have all edges connected to 'v->e' */
- verts[0] = v;
- for (i = 1; i < maxindex; i++) {
- verts[i] = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
- if (copy_select) {
- BM_elem_select_copy(bm, bm, verts[i], v);
- }
- }
+ BLI_assert(edges_found <= v_edges_num);
- /* Replace v with the new verts in each group */
-#if 0
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- /* call first since its faster then a hash lookup */
- if (l->v != v) {
- continue;
- }
- i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, l->e));
- if (i == 0) {
- continue;
+ if (edges_found == v_edges_num) {
+ /* We're done! The remaining edges in 'edges' form the last fan,
+ * which can be left as is.
+ * if 'edges' were alloc'd it'd be freed here. */
+ break;
}
+ else {
+ BMVert *v_new;
- /* Loops here should always refer to an edge that has v as an
- * endpoint. For each appearance of this vert in a face, there
- * will actually be two iterations: one for the loop heading
- * towards vertex v, and another for the loop heading out from
- * vertex v. Only need to swap the vertex on one of those times,
- * on the outgoing loop. */
+ v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
+ if (copy_select) {
+ BM_elem_select_copy(bm, bm, v_new, v);
+ }
- /* XXX - because this clobbers the iterator, this *whole* block is commented, see below */
- l->v = verts[i];
- }
-#else
- /* note: this is the same as the commented code above *except* that it doesn't break iterator
- * by modifying data it loops over [#30632], this re-uses the 'stack' variable which is a bit
- * bad practice but save alloc'ing a new array - note, the comment above is useful, keep it
- * if you are tidying up code - campbell */
- STACK_INIT(stack, v_edgetot);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- if (l->v == v) {
- STACK_PUSH(stack, (BMEdge *)l);
- }
- }
- while ((l = (BMLoop *)(STACK_POP(stack)))) {
- if ((i = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&visithash, (uintptr_t)l->e)))) {
- l->v = verts[i];
- }
- }
-#endif
+ while ((e = BLI_SMALLSTACK_POP(edges))) {
+ bmesh_edge_vert_swap(e, v_new, v);
+ }
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- i = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&visithash, (uintptr_t)e));
- if (i == 0) {
- continue;
+ if (r_vout) {
+ BLI_SMALLSTACK_PUSH(verts_new, v_new);
+ }
+ verts_num += 1;
}
-
- BLI_assert(e->v1 == v || e->v2 == v);
- bmesh_disk_edge_remove(e, v);
- bmesh_edge_swapverts(e, v, verts[i]);
- bmesh_disk_edge_append(e, verts[i]);
}
- BLI_smallhash_release(&visithash);
+#undef EDGE_VISIT
- for (i = 0; i < maxindex; i++) {
- BM_CHECK_ELEMENT(verts[i]);
- }
+ /* flags are clean now, handle return values */
if (r_vout_len != NULL) {
- *r_vout_len = maxindex;
+ *r_vout_len = verts_num;
}
if (r_vout != NULL) {
+ BMVert **verts;
+
+ verts = MEM_mallocN(sizeof(BMVert *) * verts_num, __func__);
*r_vout = verts;
+
+ verts[0] = v;
+ BLI_SMALLSTACK_AS_TABLE(verts_new, &verts[1]);
}
}
/**
+ * Utility function for #BM_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.
+ *
+ * \param edges_separate
+ * A list-of-lists, each list is from a single original edge (the first edge is the original),
+ * Check for duplicates (not just with the first) but between all.
+ * This is O(n2) but radial edges are very rarely >2 and almost never >~10.
+ *
+ * \note typically its best to avoid creating the data in the first place,
+ * but inspecting all loops connectivity is quite involved.
+ *
+ * \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)
+{
+ do {
+ LinkNode *n_orig = edges_separate->link;
+ do {
+ BMEdge *e_orig = n_orig->link;
+ LinkNode *n_step = n_orig->next;
+ LinkNode *n_prev = n_orig;
+ 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);
+ n_prev->next = n_step->next;
+ n_step = n_prev;
+ }
+ } while ((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
*/
-void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- BMEdge **e_in, int e_in_len)
+void BM_vert_separate(
+ BMesh *bm, BMVert *v,
+ BMEdge **e_in, int e_in_len,
+ const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len)
{
+ LinkNode *edges_separate = NULL;
int i;
for (i = 0; i < e_in_len; i++) {
BMEdge *e = e_in[i];
- if (e->l && BM_vert_in_edge(e, v)) {
- bmesh_edge_separate(bm, e, e->l, false);
+ if (bm_edge_supports_separate(e)) {
+ LinkNode *edges_orig = NULL;
+ do {
+ BMLoop *l_sep = e->l;
+ bmesh_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));
+ BLI_linklist_prepend_alloca(&edges_orig, e);
+ BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
}
}
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, false);
+ bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+ if (edges_separate) {
+ bmesh_vert_separate__cleanup(bm, edges_separate);
+ }
+}
+
+
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v,
+ const char hflag,
+ const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len)
+{
+ LinkNode *edges_separate = NULL;
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+ do {
+ if (BM_elem_flag_test(e_iter, hflag)) {
+ BMEdge *e = e_iter;
+ if (bm_edge_supports_separate(e)) {
+ LinkNode *edges_orig = NULL;
+ do {
+ BMLoop *l_sep = e->l;
+ bmesh_edge_separate(bm, e, l_sep, copy_select);
+ /* trick to avoid looping over seperated edges */
+ if (edges_separate == NULL && edges_orig == NULL) {
+ e_first = l_sep->e;
+ }
+ BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
+ BLI_assert(e != l_sep->e);
+ } while (bm_edge_supports_separate(e));
+ BLI_linklist_prepend_alloca(&edges_orig, e);
+ BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+
+ bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+ if (edges_separate) {
+ bmesh_vert_separate__cleanup(bm, edges_separate);
+ }
}
+/** \} */
+
+
/**
* \brief Splice Edge
*
* Splice two unique edges which share the same two vertices into one edge.
+ * (\a e_src into \a e_dst, removing e_src).
*
* \return Success
*
* \note Edges must already have the same vertices.
*/
-bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
+bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
{
BMLoop *l;
- if (!BM_vert_in_edge(e, e_target->v1) || !BM_vert_in_edge(e, e_target->v2)) {
+ if (!BM_vert_in_edge(e_src, e_dst->v1) || !BM_vert_in_edge(e_src, e_dst->v2)) {
/* not the same vertices can't splice */
/* the caller should really make sure this doesn't happen ever
@@ -2224,21 +2322,21 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
return false;
}
- while (e->l) {
- l = e->l;
- BLI_assert(BM_vert_in_edge(e_target, l->v));
- BLI_assert(BM_vert_in_edge(e_target, l->next->v));
- bmesh_radial_loop_remove(l, e);
- bmesh_radial_append(e_target, l);
+ while (e_src->l) {
+ l = e_src->l;
+ BLI_assert(BM_vert_in_edge(e_dst, l->v));
+ BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
+ bmesh_radial_loop_remove(l, e_src);
+ bmesh_radial_append(e_dst, l);
}
- BLI_assert(bmesh_radial_length(e->l) == 0);
+ BLI_assert(bmesh_radial_length(e_src->l) == 0);
- BM_CHECK_ELEMENT(e);
- BM_CHECK_ELEMENT(e_target);
+ BM_CHECK_ELEMENT(e_src);
+ BM_CHECK_ELEMENT(e_dst);
/* removes from disks too */
- BM_edge_kill(bm, e);
+ BM_edge_kill(bm, e_src);
return true;
}
@@ -2254,8 +2352,9 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
* \note Does nothing if \a l_sep is already the only loop in the
* edge radial.
*/
-void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
- const bool copy_select)
+void bmesh_edge_separate(
+ BMesh *bm, BMEdge *e, BMLoop *l_sep,
+ const bool copy_select)
{
BMEdge *e_new;
#ifndef NDEBUG
@@ -2266,7 +2365,7 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
BLI_assert(e->l);
if (BM_edge_is_boundary(e)) {
- /* no cut required */
+ BLI_assert(0); /* no cut required */
return;
}
@@ -2299,72 +2398,245 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
*/
BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
{
- BMVert **vtar;
- int len, i;
BMVert *v_new = NULL;
BMVert *v_sep = l_sep->v;
+ BMEdge *e_iter;
+ BMEdge *edges[2];
+ int i;
/* peel the face from the edge radials on both sides of the
* loop vert, disconnecting the face from its fan */
bmesh_edge_separate(bm, l_sep->e, l_sep, false);
bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
- if (bmesh_disk_count(v_sep) == 2) {
- /* If there are still only two edges out of v_sep, then
- * this whole URMV was just a no-op, so exit now. */
+ /* do inline, below */
+#if 0
+ if (BM_vert_edge_count_is_equal(v_sep, 2)) {
return v_sep;
}
+#endif
- /* Update the disk start, so that v->e points to an edge
- * not touching the split loop. This is so that BM_vert_split
- * will leave the original v_sep on some *other* fan (not the
- * one-face fan that holds the unglue face). */
- while (v_sep->e == l_sep->e || v_sep->e == l_sep->prev->e) {
- v_sep->e = bmesh_disk_edge_next(v_sep->e, v_sep);
+ /* Search for an edge unattached to this loop */
+ e_iter = v_sep->e;
+ while (!ELEM(e_iter, l_sep->e, l_sep->prev->e)) {
+ e_iter = bmesh_disk_edge_next(e_iter, v_sep);
+
+ /* We've come back around to the initial edge, all touch this loop.
+ * If there are still only two edges out of v_sep,
+ * then this whole URMV was just a no-op, so exit now. */
+ if (e_iter == v_sep->e) {
+ BLI_assert(BM_vert_edge_count_is_equal(v_sep, 2));
+ return v_sep;
+ }
}
- /* Split all fans connected to the vert, duplicating it for
- * each fans. */
- bmesh_vert_separate(bm, v_sep, &vtar, &len, false);
+ v_sep->e = l_sep->e;
- /* There should have been at least two fans cut apart here,
- * otherwise the early exit would have kicked in. */
- BLI_assert(len >= 2);
+ v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
- v_new = l_sep->v;
+ edges[0] = l_sep->e;
+ edges[1] = l_sep->prev->e;
- /* Desired result here is that a new vert should always be
- * created for the unglue face. This is so we can glue any
- * extras back into the original vert. */
- BLI_assert(v_new != v_sep);
- BLI_assert(v_sep == vtar[0]);
+ for (i = 0; i < ARRAY_SIZE(edges); i++) {
+ BMEdge *e = edges[i];
+ bmesh_edge_vert_swap(e, v_new, v_sep);
+ }
- /* If there are more than two verts as a result, glue together
- * all the verts except the one this URMV intended to create */
- if (len > 2) {
- for (i = 0; i < len; i++) {
- if (vtar[i] == v_new) {
- break;
+ BLI_assert(v_sep != l_sep->v);
+ BLI_assert(v_sep->e != l_sep->v->e);
+
+ BM_CHECK_ELEMENT(l_sep);
+ BM_CHECK_ELEMENT(v_sep);
+ BM_CHECK_ELEMENT(edges[0]);
+ BM_CHECK_ELEMENT(edges[1]);
+ BM_CHECK_ELEMENT(v_new);
+
+ return v_new;
+}
+
+/**
+ * A version of #bmesh_urmv_loop that disconnects multiple loops at once.
+ *
+ * Handles the task of finding fans boundaries.
+ */
+BMVert *bmesh_urmv_loop_multi(
+ BMesh *bm, BMLoop **larr, int larr_len)
+{
+ BMVert *v_sep = larr[0]->v;
+ BMVert *v_new;
+ int i;
+ bool is_mixed_any = false;
+
+ BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+
+#define LOOP_VISIT _FLAG_WALK
+#define EDGE_VISIT _FLAG_WALK
+
+ for (i = 0; i < larr_len; i++) {
+ BMLoop *l_sep = larr[i];
+
+ /* all must be from the same vert! */
+ BLI_assert(v_sep == l_sep->v);
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(l_sep, LOOP_VISIT);
+
+ /* weak! but it makes it simpler to check for edges to split
+ * 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++) {
+ 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);
+
+ l_iter = l_first = e->l;
+ do {
+ if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ is_mixed = true;
+ is_mixed_any = true;
+ break;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+
+ if (is_mixed) {
+ /* 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;
+ }
+ BLI_SMALLSTACK_PUSH(edges, e);
}
}
+ }
+
+ if (is_mixed_any == false) {
+ /* all loops in 'larr' are the soul 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))) {
+ 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);
+
+ 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];
- if (i != len) {
- /* Swap the single vert that was needed for the
- * unglue into the last array slot */
- SWAP(BMVert *, vtar[i], vtar[len - 1]);
+ if (e->v1 == v_sep) {
+ e_new_v_pair[0] = v_new;
+ e_new_v_pair[1] = e->v2;
+ }
+ else {
+ BLI_assert(v_sep == e->v2);
+ e_new_v_pair[0] = e->v1;
+ e_new_v_pair[1] = v_new;
+ }
- /* And then glue the rest back together */
- for (i = 1; i < len - 1; i++) {
- BM_vert_splice(bm, vtar[i], vtar[0]);
+ e_new = BM_edge_create(bm, UNPACK2(e_new_v_pair), e, BM_CREATE_NOP);
+
+ /* now moved all loops from 'larr' to this newly created edge */
+ l_iter = l_first = e->l;
+ do {
+ l_next = l_iter->radial_next;
+ if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ bmesh_radial_loop_remove(l_iter, e);
+ bmesh_radial_append(e_new, l_iter);
+ l_iter->e = e_new;
+ }
+ } while ((l_iter = l_next) != l_first);
+ }
+ else {
+ /* we own the edge entirely, replace the vert */
+ bmesh_disk_vert_replace(e, v_new, v_sep);
}
+
+ /* loop vert is handled last! */
}
}
- MEM_freeN(vtar);
+ for (i = 0; i < larr_len; i++) {
+ BMLoop *l_sep = larr[i];
+
+ l_sep->v = v_new;
+
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT));
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->prev, LOOP_VISIT));
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->next, LOOP_VISIT));
+ BM_ELEM_API_FLAG_DISABLE(l_sep, LOOP_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->prev, LOOP_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->next, LOOP_VISIT);
+
+
+ BM_ELEM_API_FLAG_DISABLE(l_sep->prev->e, EDGE_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->e, EDGE_VISIT);
+ }
+
+#undef LOOP_VISIT
+#undef EDGE_VISIT
+
+ return v_new;
+}
+
+static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ BMLoop *l_iter, *l_first;
+
+ BLI_assert(ELEM(v_src, e->v1, e->v2));
+ bmesh_disk_vert_replace(e, v_dst, v_src);
+
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v_src) {
+ l_iter->v = v_dst;
+ if (BM_vert_in_edge(l_iter->prev->e, v_src)) {
+ bmesh_edge_vert_swap__recursive(l_iter->prev->e, v_dst, v_src);
+ }
+ }
+ else if (l_iter->next->v == v_src) {
+ l_iter->next->v = v_dst;
+ if (BM_vert_in_edge(l_iter->next->e, v_src)) {
+ bmesh_edge_vert_swap__recursive(l_iter->next->e, v_dst, v_src);
+ }
+ }
+ else {
+ BLI_assert(l_iter->prev->v != v_src);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+}
+/**
+ * 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.
+ */
+BMVert *bmesh_urmv_loop_region(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 */
+ bmesh_edge_vert_swap__recursive(l_sep->e, v_new, l_sep->v);
+ BLI_assert(l_sep->v == v_new);
return v_new;
}
+
/**
* \brief Unglue Region Make Vert (URMV)
*
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index ab847fc82eb..2b100eb7b8d 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -27,8 +27,9 @@
* \ingroup bmesh
*/
-BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f,
- const bool copy_verts, const bool copy_edges);
+BMFace *BM_face_copy(
+ BMesh *bm_dst, BMesh *bm_src, BMFace *f,
+ const bool copy_verts, const bool copy_edges);
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
@@ -40,15 +41,19 @@ typedef enum eBMCreateFlag {
BM_CREATE_SKIP_CD = (1 << 2),
} eBMCreateFlag;
-BMVert *BM_vert_create(BMesh *bm, const float co[3],
- const BMVert *v_example, const eBMCreateFlag create_flag);
-BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
- const BMEdge *e_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_verts(BMesh *bm, BMVert **verts, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool create_edges);
+BMVert *BM_vert_create(
+ BMesh *bm, const float co[3],
+ const BMVert *v_example, const eBMCreateFlag create_flag);
+BMEdge *BM_edge_create(
+ BMesh *bm, BMVert *v1, BMVert *v2,
+ const BMEdge *e_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create(
+ BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_verts(
+ BMesh *bm, BMVert **verts, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool create_edges);
void BM_face_edges_kill(BMesh *bm, BMFace *f);
void BM_face_verts_kill(BMesh *bm, BMFace *f);
@@ -57,25 +62,32 @@ 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, BMEdge *e_target);
-bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target);
+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_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select);
bool bmesh_loop_reverse(BMesh *bm, BMFace *f);
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
-void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- BMEdge **e_in, int e_in_len);
+void BM_vert_separate(
+ BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len);
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v, const char hflag, const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len);
/* EULER API - For modifying structure */
-BMFace *bmesh_sfme(BMesh *bm, BMFace *f,
- BMLoop *l1, BMLoop *l2,
- BMLoop **r_l,
+BMFace *bmesh_sfme(
+ BMesh *bm, BMFace *f,
+ BMLoop *l1, BMLoop *l2,
+ BMLoop **r_l,
#ifdef USE_BMESH_HOLES
ListBase *holes,
#endif
@@ -84,11 +96,15 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f,
);
BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
-BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_splice);
+BMEdge *bmesh_jekv(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_splice);
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);
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index aa1f511e8d7..eaa070151a6 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -52,8 +52,9 @@ typedef struct BMEdgeLoopStore {
/* -------------------------------------------------------------------- */
/* BM_mesh_edgeloops_find & Util Functions */
-static int bm_vert_other_tag(BMVert *v, BMVert *v_prev,
- BMEdge **r_e)
+static int bm_vert_other_tag(
+ BMVert *v, BMVert *v_prev,
+ BMEdge **r_e)
{
BMIter iter;
BMEdge *e, *e_next = NULL;
@@ -125,8 +126,9 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
/**
* \return listbase of listbases, each linking to a vertex.
*/
-int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
+int BM_mesh_edgeloops_find(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
{
BMIter iter;
BMEdge *e;
@@ -183,8 +185,9 @@ struct VertStep {
BMVert *v;
};
-static void vs_add(BLI_mempool *vs_pool, ListBase *lb,
- BMVert *v, BMEdge *e_prev, const int iter_tot)
+static void vs_add(
+ BLI_mempool *vs_pool, ListBase *lb,
+ BMVert *v, BMEdge *e_prev, const int iter_tot)
{
struct VertStep *vs_new = BLI_mempool_alloc(vs_pool);
vs_new->v = v;
@@ -256,9 +259,10 @@ static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const in
return (BLI_listbase_is_empty(lb) == false);
}
-bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
- BMVert *v_src, BMVert *v_dst)
+bool BM_mesh_edgeloops_find_path(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
+ BMVert *v_src, BMVert *v_dst)
{
BMIter iter;
BMEdge *e;
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 527dba120e1..5df4ee5848e 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -32,17 +32,20 @@ struct ListBase;
struct BMEdgeLoopStore;
/* multiple edgeloops (ListBase) */
-int BM_mesh_edgeloops_find(BMesh *bm, struct ListBase *r_lb,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data);
-bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
- BMVert *v_src, BMVert *v_dst);
+int BM_mesh_edgeloops_find(
+ BMesh *bm, struct ListBase *r_lb,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data);
+bool BM_mesh_edgeloops_find_path(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
+ BMVert *v_src, BMVert *v_dst);
void BM_mesh_edgeloops_free(struct ListBase *eloops);
void BM_mesh_edgeloops_calc_center(BMesh *bm, struct ListBase *eloops);
void BM_mesh_edgeloops_calc_normal(BMesh *bm, struct ListBase *eloops);
-void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, struct ListBase *eloops,
- const float no_align[3]);
+void BM_mesh_edgeloops_calc_normal_aligned(
+ BMesh *bm, struct ListBase *eloops,
+ const float no_align[3]);
void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const bool use_normals);
@@ -59,8 +62,9 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
-bool BM_edgeloop_calc_normal_aligned(BMesh *bm, struct BMEdgeLoopStore *el_store,
- const float no_align[3]);
+bool BM_edgeloop_calc_normal_aligned(
+ BMesh *bm, struct BMEdgeLoopStore *el_store,
+ const float no_align[3]);
void BM_edgeloop_flip(BMesh *bm, struct BMEdgeLoopStore *el_store);
void BM_edgeloop_expand(BMesh *bm, struct BMEdgeLoopStore *el_store, int el_store_len);
diff --git a/source/blender/bmesh/intern/bmesh_inline.h b/source/blender/bmesh/intern/bmesh_inline.h
index 96b2cd396a2..4b55060875b 100644
--- a/source/blender/bmesh/intern/bmesh_inline.h
+++ b/source/blender/bmesh/intern/bmesh_inline.h
@@ -39,11 +39,13 @@
#define BM_elem_flag_merge( ele_a, ele_b) _bm_elem_flag_merge (&(ele_a)->head, &(ele_b)->head)
#define BM_elem_flag_merge_into(ele, ele_a, ele_b)_bm_elem_flag_merge_into (&(ele)->head, &(ele_a)->head, &(ele_b)->head)
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE char _bm_elem_flag_test(const BMHeader *head, const char hflag)
{
return head->hflag & hflag;
}
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE bool _bm_elem_flag_test_bool(const BMHeader *head, const char hflag)
{
return (head->hflag & hflag) != 0;
@@ -116,6 +118,7 @@ BLI_INLINE void _bm_elem_index_set(BMHeader *head, const int index)
head->index = index;
}
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE int _bm_elem_index_get(const BMHeader *head)
{
return head->index;
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index f745972293e..30ac76ab7e1 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -241,8 +241,9 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, con
* y
* </pre>
*/
-static int compute_mdisp_quad(BMLoop *l, float v1[3], float v2[3], float v3[3], float v4[3],
- float e1[3], float e2[3])
+static int compute_mdisp_quad(
+ BMLoop *l, float v1[3], float v2[3], float v3[3], float v4[3],
+ float e1[3], float e2[3])
{
float cent[3], n[3], p[3];
@@ -302,9 +303,10 @@ static float quad_coord(const float aa[3], const float bb[3], const float cc[3],
return f1;
}
-static int quad_co(float *x, float *y,
- const float v1[3], const float v2[3], const float v3[3], const float v4[3],
- const float p[3], const float n[3])
+static int quad_co(
+ float *r_x, float *r_y,
+ const float v1[3], const float v2[3], const float v3[3], const float v4[3],
+ const float p[3], const float n[3])
{
float projverts[5][3], n2[3];
float dprojverts[4][3], origin[3] = {0.0f, 0.0f, 0.0f};
@@ -340,14 +342,15 @@ static int quad_co(float *x, float *y,
return 0;
}
- *y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
- *x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
+ *r_y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
+ *r_x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
return 1;
}
-static void mdisp_axis_from_quad(float v1[3], float v2[3], float UNUSED(v3[3]), float v4[3],
- float axis_x[3], float axis_y[3])
+static void mdisp_axis_from_quad(
+ float v1[3], float v2[3], float UNUSED(v3[3]), float v4[3],
+ float axis_x[3], float axis_y[3])
{
sub_v3_v3v3(axis_x, v4, v1);
sub_v3_v3v3(axis_y, v2, v1);
@@ -358,8 +361,9 @@ static void mdisp_axis_from_quad(float v1[3], float v2[3], float UNUSED(v3[3]),
/* tl is loop to project onto, l is loop whose internal displacement, co, is being
* projected. x and y are location in loop's mdisps grid of point co. */
-static bool mdisp_in_mdispquad(BMLoop *l, BMLoop *tl, float p[3], float *x, float *y,
- int res, float axis_x[3], float axis_y[3])
+static bool mdisp_in_mdispquad(
+ BMLoop *l, BMLoop *tl, float p[3], float *x, float *y,
+ int res, float axis_x[3], float axis_y[3])
{
float v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
float eps = FLT_EPSILON * 4000;
@@ -392,8 +396,9 @@ static bool mdisp_in_mdispquad(BMLoop *l, BMLoop *tl, float p[3], float *x, floa
return 1;
}
-static float bm_loop_flip_equotion(float mat[2][2], float b[2], const float target_axis_x[3], const float target_axis_y[3],
- const float coord[3], int i, int j)
+static float bm_loop_flip_equotion(
+ float mat[2][2], float b[2], const float target_axis_x[3], const float target_axis_y[3],
+ const float coord[3], int i, int j)
{
mat[0][0] = target_axis_x[i];
mat[0][1] = target_axis_y[i];
@@ -405,8 +410,9 @@ static float bm_loop_flip_equotion(float mat[2][2], float b[2], const float targ
return mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0];
}
-static void bm_loop_flip_disp(const float source_axis_x[3], const float source_axis_y[3],
- const float target_axis_x[3], const float target_axis_y[3], float disp[3])
+static void bm_loop_flip_disp(
+ const float source_axis_x[3], const float source_axis_y[3],
+ const float target_axis_x[3], const float target_axis_y[3], float disp[3])
{
float vx[3], vy[3], coord[3];
float n[3], vec[3];
@@ -453,8 +459,8 @@ static void bm_loop_interp_mdisps(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
/* if no disps data allocate a new grid, the size of the first grid in f_src. */
if (!md_dst->totdisp) {
- MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
-
+ const MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
+
md_dst->totdisp = md_src->totdisp;
md_dst->level = md_src->level;
if (md_dst->totdisp) {
@@ -1051,7 +1057,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(
mul_vn_fl(lf->data_weights, lf->data_len, 1.0f / lwc.weight_accum);
}
else {
- fill_vn_fl(lf->data_weights, lf->data_len, 1.0f / (float)lf->data_len);
+ copy_vn_fl(lf->data_weights, lf->data_len, 1.0f / (float)lf->data_len);
}
BLI_linklist_prepend_arena(&groups, lf, lwc.arena);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 4dc27d75a55..0abf41709a0 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -136,8 +136,9 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
*
* Sometimes its convenient to get the iterator as an array.
*/
-int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- void **array, const int len)
+int BMO_iter_as_array(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ void **array, const int len)
{
int i = 0;
@@ -169,9 +170,10 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
*
* Caller needs to free the array.
*/
-void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size)
+void *BM_iter_as_arrayN(
+ BMesh *bm, const char itype, void *data, int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size)
{
BMIter iter;
@@ -212,10 +214,11 @@ void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
}
}
-void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size)
+void *BMO_iter_as_arrayN(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size)
{
BMOIter iter;
BMElem *ele;
@@ -273,8 +276,9 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
*
* Counts how many flagged / unflagged items are found in this element.
*/
-int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data,
- const short oflag, const bool value)
+int BMO_iter_elem_count_flag(
+ BMesh *bm, const char itype, void *data,
+ const short oflag, const bool value)
{
BMIter iter;
BMElemF *ele;
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 49e511bdcb5..c4b184ef8b8 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -197,14 +197,17 @@ typedef struct BMIter {
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
-void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
- void **stack_array, int stack_array_size) ATTR_WARN_UNUSED_RESULT;
-int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- void **array, const int len);
-void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size);
+void *BM_iter_as_arrayN(
+ BMesh *bm, const char itype, void *data, int *r_len,
+ void **stack_array, int stack_array_size) ATTR_WARN_UNUSED_RESULT;
+int BMO_iter_as_array(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ void **array, const int len);
+void *BMO_iter_as_arrayN(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size);
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value);
int BM_iter_mesh_count(const char itype, BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h
index d3e18b97acb..e68440021e6 100644
--- a/source/blender/bmesh/intern/bmesh_iterators_inline.h
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h
@@ -37,6 +37,7 @@
*
* Calls an iterators step function to return the next element.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BM_iter_step(BMIter *iter)
{
return iter->step(iter);
@@ -50,6 +51,7 @@ BLI_INLINE void *BM_iter_step(BMIter *iter)
* it with the appropriate function pointers based
* upon its type.
*/
+ATTR_NONNULL(1)
BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *data)
{
/* int argtype; */
@@ -169,6 +171,7 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da
* to return the first element of the iterator.
*
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BM_iter_new(BMIter *iter, BMesh *bm, const char itype, void *data)
{
if (LIKELY(BM_iter_init(iter, bm, itype, data))) {
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 158c2aa4263..1f64f7b74cc 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -115,8 +115,8 @@ struct BMLog {
typedef struct {
float co[3];
short no[3];
- float mask;
char hflag;
+ float mask;
} BMLogVert;
typedef struct {
@@ -126,6 +126,10 @@ typedef struct {
/************************* Get/set element IDs ************************/
+/* bypass actual hashing, the keys don't overlap */
+#define logkey_hash BLI_ghashutil_inthash_p_simple
+#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)
{
@@ -386,12 +390,12 @@ static BMLogEntry *bm_log_entry_create(void)
{
BMLogEntry *entry = MEM_callocN(sizeof(BMLogEntry), __func__);
- entry->deleted_verts = BLI_ghash_ptr_new(__func__);
- entry->deleted_faces = BLI_ghash_ptr_new(__func__);
- entry->added_verts = BLI_ghash_ptr_new(__func__);
- entry->added_faces = BLI_ghash_ptr_new(__func__);
- entry->modified_verts = BLI_ghash_ptr_new(__func__);
- entry->modified_faces = BLI_ghash_ptr_new(__func__);
+ entry->deleted_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->deleted_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->added_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->added_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->modified_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->modified_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
entry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 0, 64, BLI_MEMPOOL_NOP);
entry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 0, 64, BLI_MEMPOOL_NOP);
@@ -476,10 +480,11 @@ 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);
log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1);
- log->id_to_elem = BLI_ghash_ptr_new_ex(__func__, (unsigned int)(bm->totvert + bm->totface));
- log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, (unsigned int)(bm->totvert + bm->totface));
+ log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
+ log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, reserve_num);
/* Assign IDs to all existing vertices and faces */
bm_log_assign_ids(bm, log);
@@ -588,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)
{
- void *varr;
- void *farr;
+ unsigned int *varr;
+ unsigned int *farr;
GHash *id_to_idx;
@@ -597,41 +602,37 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
- int i;
+ unsigned int i;
/* Put all vertex IDs into an array */
- i = 0;
varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__);
- BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
- ((unsigned int *)varr)[i++] = bm_log_vert_id_get(log, v);
+ BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
+ varr[i] = bm_log_vert_id_get(log, v);
}
/* Put all face IDs into an array */
- i = 0;
farr = MEM_mallocN(sizeof(int) * (size_t)bm->totface, __func__);
- BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
- ((unsigned int *)farr)[i++] = bm_log_face_id_get(log, f);
+ BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
+ farr[i] = bm_log_face_id_get(log, f);
}
/* Create BMVert index remap array */
id_to_idx = bm_log_compress_ids_to_indices(varr, (unsigned int)bm->totvert);
- i = 0;
- BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
+ 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);
const void *val = BLI_ghash_lookup(id_to_idx, key);
- ((unsigned int *)varr)[i++] = GET_UINT_FROM_POINTER(val);
+ varr[i] = GET_UINT_FROM_POINTER(val);
}
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);
- i = 0;
- BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
+ 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);
const void *val = BLI_ghash_lookup(id_to_idx, key);
- ((unsigned int *)farr)[i++] = GET_UINT_FROM_POINTER(val);
+ farr[i] = GET_UINT_FROM_POINTER(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
@@ -836,14 +837,15 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
BMLogVert *lv;
unsigned int v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
+ void **val_p;
/* Find or create the BMLogVert entry */
if ((lv = BLI_ghash_lookup(entry->added_verts, key))) {
bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
}
- else if (!BLI_ghash_haskey(entry->modified_verts, key)) {
+ else if (!BLI_ghash_ensure_p(entry->modified_verts, key, &val_p)) {
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
- BLI_ghash_insert(entry->modified_verts, key, lv);
+ *val_p = lv;
}
}
@@ -987,6 +989,15 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
+ /* 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);
+ }
+
+ if (BLI_ghash_size(log->current_entry->added_faces) == 0) {
+ BLI_ghash_reserve(log->current_entry->added_faces, (unsigned int)bm->totface);
+ }
+
/* Log all vertices as newly created */
BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
BM_log_vert_added(log, v, cd_vert_mask_offset);
@@ -1071,6 +1082,24 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
return lv->mask;
}
+void BM_log_original_vert_data(
+ BMLog *log, BMVert *v,
+ const float **r_co, const short **r_no)
+{
+ BMLogEntry *entry = log->current_entry;
+ const BMLogVert *lv;
+ unsigned v_id = bm_log_vert_id_get(log, v);
+ void *key = SET_UINT_IN_POINTER(v_id);
+
+ BLI_assert(entry);
+
+ BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+
+ lv = BLI_ghash_lookup(entry->modified_verts, key);
+ *r_co = lv->co;
+ *r_no = lv->no;
+}
+
/************************ Debugging and Testing ***********************/
/* For internal use only (unit testing) */
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 2147b5c64b4..dd1772af068 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -96,6 +96,11 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
float BM_log_original_mask(BMLog *log, BMVert *v);
+/* Get the logged data of a vertex (avoid multiple lookups) */
+void BM_log_original_vert_data(
+ BMLog *log, BMVert *v,
+ const float **r_co, const short **r_no);
+
/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log);
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 8aa64906019..17b6d1d99e7 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -73,9 +73,9 @@ static void recount_totsels(BMesh *bm)
/** \name BMesh helper functions for selection flushing.
* \{ */
-static bool bm_vert_is_edge_select_any_other(BMVert *v, BMEdge *e_first)
+static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
{
- BMEdge *e_iter = e_first;
+ const BMEdge *e_iter = e_first;
/* start by stepping over the current edge */
while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
@@ -87,10 +87,10 @@ static bool bm_vert_is_edge_select_any_other(BMVert *v, BMEdge *e_first)
}
#if 0
-static bool bm_vert_is_edge_select_any(BMVert *v)
+static bool bm_vert_is_edge_select_any(const BMVert *v)
{
if (v->e) {
- BMEdge *e_iter, *e_first;
+ const BMEdge *e_iter, *e_first;
e_iter = e_first = v->e;
do {
if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
@@ -104,7 +104,7 @@ static bool bm_vert_is_edge_select_any(BMVert *v)
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
{
- BMLoop *l_iter = l_first;
+ const BMLoop *l_iter = l_first;
/* start by stepping over the current face */
while ((l_iter = l_iter->radial_next) != l_first) {
@@ -116,10 +116,10 @@ static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
}
#if 0
-static bool bm_edge_is_face_select_any(BMEdge *e)
+static bool bm_edge_is_face_select_any(const BMEdge *e)
{
if (e->l) {
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
@@ -626,8 +626,9 @@ void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
/**
* counts number of elements with flag enabled/disabled
*/
-static int bm_mesh_flag_count(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool test_for_enabled)
+static int bm_mesh_flag_count(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool test_for_enabled)
{
BMElem *ele;
BMIter iter;
@@ -913,6 +914,12 @@ void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
BLI_addtail(&(bm->selected), ese);
}
+void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
+{
+ BMEditSelection *ese = bm_select_history_create(ele);
+ BLI_addhead(&(bm->selected), ese);
+}
+
void _bm_select_history_store(BMesh *bm, BMHeader *ele)
{
if (!BM_select_history_check(bm, (BMElem *)ele)) {
@@ -920,6 +927,12 @@ void _bm_select_history_store(BMesh *bm, BMHeader *ele)
}
}
+void _bm_select_history_store_head(BMesh *bm, BMHeader *ele)
+{
+ if (!BM_select_history_check(bm, (BMElem *)ele)) {
+ BM_select_history_store_head_notest(bm, (BMElem *)ele);
+ }
+}
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
{
@@ -1013,8 +1026,9 @@ GHash *BM_select_history_map_create(BMesh *bm)
return map;
}
-void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test)
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1084,8 +1098,9 @@ void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hfl
}
}
-void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test)
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1139,15 +1154,17 @@ void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hfla
}
}
-void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide)
+void BM_mesh_elem_hflag_disable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide)
{
/* call with 0 hflag_test */
BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
}
-void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide)
+void BM_mesh_elem_hflag_enable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide)
{
/* call with 0 hflag_test */
BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 15f972c6435..4730af66a74 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -43,15 +43,19 @@ void BM_face_hide_set(BMFace *f, const bool hide);
/* Selection code */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
-void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test);
-void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test);
-
-void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide);
-void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide);
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test);
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test);
+
+void BM_mesh_elem_hflag_enable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide);
+void BM_mesh_elem_hflag_disable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide);
/* individual element select functions, BM_elem_select_set is a shortcut for these
* that automatically detects which one to use*/
@@ -91,6 +95,8 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
#define BM_select_history_remove(bm, ele) _bm_select_history_remove(bm, &(ele)->head)
#define BM_select_history_store_notest(bm, ele) _bm_select_history_store_notest(bm, &(ele)->head)
#define BM_select_history_store(bm, ele) _bm_select_history_store(bm, &(ele)->head)
+#define BM_select_history_store_head_notest(bm, ele) _bm_select_history_store_head_notest(bm, &(ele)->head)
+#define BM_select_history_store_head(bm, ele) _bm_select_history_store_head(bm, &(ele)->head)
#define BM_select_history_store_after_notest(bm, ese_ref, ele) _bm_select_history_store_after_notest(bm, ese_ref, &(ele)->head)
#define BM_select_history_store_after(bm, ese, ese_ref) _bm_select_history_store_after(bm, ese_ref, &(ele)->head)
@@ -98,6 +104,8 @@ bool _bm_select_history_check(BMesh *bm, const BMHeader *ele);
bool _bm_select_history_remove(BMesh *bm, BMHeader *ele);
void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele);
void _bm_select_history_store(BMesh *bm, BMHeader *ele);
+void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele);
+void _bm_select_history_store_head(BMesh *bm, BMHeader *ele);
void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele);
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 9a2869b64ef..2c4a98b0b7e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -303,8 +303,9 @@ static void bm_mesh_edges_calc_vectors(BMesh *bm, float (*edgevec)[3], const flo
bm->elem_index_dirty &= ~BM_EDGE;
}
-static void bm_mesh_verts_calc_normals(BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
- const float (*vcos)[3], float (*vnos)[3])
+static void bm_mesh_verts_calc_normals(
+ BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
+ const float (*vcos)[3], float (*vnos)[3])
{
BM_mesh_elem_index_ensure(bm, (vnos) ? (BM_EDGE | BM_VERT) : BM_EDGE);
@@ -437,8 +438,9 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
/**
* Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normals_vnos
*/
-static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
- float (*r_lnos)[3])
+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;
@@ -1131,8 +1133,9 @@ finally:
* These functions ensure its correct and are called more often in debug mode.
*/
-void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
- const char *msg_a, const char *msg_b)
+void BM_mesh_elem_index_validate(
+ BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1379,6 +1382,41 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index)
return BLI_mempool_findelem(bm->fpool, index);
}
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_VERT) == 0) {
+ return (index < bm->totvert) ? bm->vtable[index] : NULL;
+ }
+ else {
+ return BM_vert_at_index_find(bm, index);
+ }
+}
+
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_EDGE) == 0) {
+ return (index < bm->totedge) ? bm->etable[index] : NULL;
+ }
+ else {
+ return BM_edge_at_index_find(bm, index);
+ }
+}
+
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_FACE) == 0) {
+ return (index < bm->totface) ? bm->ftable[index] : NULL;
+ }
+ else {
+ return BM_face_at_index_find(bm, index);
+ }
+}
+
/**
* Return the amount of element of type 'type' in a given bmesh.
@@ -1459,7 +1497,7 @@ void BM_mesh_remap(
BMVert *new_vep = verts_pool[*new_idx];
*new_vep = *ve;
/* 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, (void *)*vep, (void *)new_vep);
+ BLI_ghash_insert(vptr_map, *vep, new_vep);
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
@@ -1490,7 +1528,7 @@ void BM_mesh_remap(
for (i = totedge; i--; new_idx--, ed--, edp--) {
BMEdge *new_edp = edges_pool[*new_idx];
*new_edp = *ed;
- BLI_ghash_insert(eptr_map, (void *)*edp, (void *)new_edp);
+ 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);*/
}
bm->elem_index_dirty |= BM_EDGE;
@@ -1522,7 +1560,7 @@ void BM_mesh_remap(
for (i = totface; i--; new_idx--, fa--, fap--) {
BMFace *new_fap = faces_pool[*new_idx];
*new_fap = *fa;
- BLI_ghash_insert(fptr_map, (void *)*fap, (void *)new_fap);
+ BLI_ghash_insert(fptr_map, *fap, new_fap);
}
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bac5da8347e..b157237c7d0 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -49,8 +49,9 @@ void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
-void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
- const char *msg_a, const char *msg_b);
+void BM_mesh_elem_index_validate(
+ BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b);
#ifndef NDEBUG
bool BM_mesh_elem_table_check(BMesh *bm);
@@ -68,6 +69,10 @@ BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
+
// XXX
int BM_mesh_elem_count(BMesh *bm, const char htype);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 3630bb78b8a..24d70cefb2e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -200,8 +200,9 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
-static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(
+ MPoly *mp, MLoop *ml,
+ BMesh *bm, BMVert **vtable, BMEdge **etable)
{
BMVert **verts = BLI_array_alloca(verts, mp->totloop);
BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
@@ -221,8 +222,9 @@ static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
*
* \warning This function doesn't calculate face normals.
*/
-void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
- const bool calc_face_normal, const bool set_key, int act_key_nr)
+void BM_mesh_bm_from_me(
+ BMesh *bm, Mesh *me,
+ const bool calc_face_normal, const bool set_key, int act_key_nr)
{
MVert *mvert;
MEdge *medge;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index ab9d7a0ccf3..ce286f6c662 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -39,8 +39,9 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
-void BM_mesh_bm_from_me(BMesh *bm, struct Mesh *me,
- const bool calc_face_normal, const bool set_key, int act_key_nr);
+void BM_mesh_bm_from_me(
+ BMesh *bm, struct Mesh *me,
+ const bool calc_face_normal, const bool set_key, int act_key_nr);
void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface);
#endif /* __BMESH_MESH_CONV_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index 3a7a4f85e99..478194735f3 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -86,20 +86,19 @@ bool BM_mesh_validate(BMesh *bm)
/* check edges */
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- BMEdge *e_other;
+ void **val_p;
if (e->v1 == e->v2) {
ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1));
}
-
/* build edgehash at the same time */
- e_other = BLI_edgehash_lookup(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
- if (e_other) {
+ if (BLI_edgehash_ensure_p(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) {
+ BMEdge *e_other = *val_p;
ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other));
}
else {
- BLI_edgehash_insert(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), e);
+ *val_p = e;
}
}
@@ -196,7 +195,7 @@ bool BM_mesh_validate(BMesh *bm)
ERRMSG("Finished - errors %d", errtot);
- return true;
+ return (errtot == 0);
}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 7b3f64dc5cd..13c43fabdb0 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -72,7 +72,8 @@
*/
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
- const int len = BM_vert_edge_count(v);
+ /* logic for 3 or more is identical */
+ const int len = BM_vert_edge_count_ex(v, 3);
if (len == 1) {
BM_vert_kill(bm, v); /* will kill edges too */
@@ -97,7 +98,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return false;
}
}
- else if (len == 2 && BM_vert_face_count(v) == 1) {
+ else if (len == 2 && BM_vert_face_count_is_equal(v, 1)) {
/* boundary vertex on a face */
return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}
@@ -269,16 +270,17 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
* the split edge to be created (must be differ and not can't be adjacent in the face).
* \param r_l pointer which will receive the BMLoop for the split edge in the new face
* \param example Edge used for attributes of splitting edge, if non-NULL
- * \param nodouble Use an existing edge if found
+ * \param no_double: Use an existing edge if found
*
* \return Pointer to the newly created face representing one side of the split
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
-BMFace *BM_face_split(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- BMLoop **r_l, BMEdge *example,
- const bool no_double)
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ BMLoop **r_l, BMEdge *example,
+ const bool no_double)
{
const bool has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
BMFace *f_new, *f_tmp;
@@ -356,10 +358,11 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f,
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
-BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- float cos[][3], int n,
- BMLoop **r_l, BMEdge *example)
+BMFace *BM_face_split_n(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ float cos[][3], int n,
+ BMLoop **r_l, BMEdge *example)
{
BMFace *f_new, *f_tmp;
BMLoop *l_dummy;
@@ -990,8 +993,9 @@ bool BM_face_split_edgenet(
*
* \returns The New Edge
*/
-BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
- const bool do_del, const bool join_faces, const bool kill_degenerate_faces)
+BMEdge *BM_vert_collapse_faces(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
+ const bool do_del, const bool join_faces, const bool kill_degenerate_faces)
{
BMEdge *e_new = NULL;
BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
@@ -1103,8 +1107,9 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float
*
* \return The New Edge
*/
-BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool kill_degenerate_faces)
+BMEdge *BM_vert_collapse_edge(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces)
{
/* nice example implementation but we want loops to have their customdata
* accounted for */
@@ -1353,8 +1358,9 @@ bool BM_face_validate(BMFace *face, FILE *err)
*
* \note #BM_edge_rotate_check must have already run.
*/
-void BM_edge_calc_rotate(BMEdge *e, const bool ccw,
- BMLoop **r_l1, BMLoop **r_l2)
+void BM_edge_calc_rotate(
+ BMEdge *e, const bool ccw,
+ BMLoop **r_l1, BMLoop **r_l2)
{
BMVert *v1, *v2;
BMFace *fa, *fb;
@@ -1516,8 +1522,9 @@ bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
return true;
}
-bool BM_edge_rotate_check_beauty(BMEdge *e,
- BMLoop *l1, BMLoop *l2)
+bool BM_edge_rotate_check_beauty(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2)
{
/* Stupid check for now:
* Could compare angles of surrounding edges
@@ -1643,3 +1650,9 @@ BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl)
{
return bmesh_urmv_loop(bm, sl);
}
+
+BMVert *BM_face_loop_separate_multi(
+ BMesh *bm, BMLoop **larr, int larr_len)
+{
+ return bmesh_urmv_loop_multi(bm, larr, larr_len);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 59aee323bba..1b826b1e0b2 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -35,24 +35,29 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v);
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
-BMFace *BM_face_split(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- BMLoop **r_l,
- BMEdge *example, const bool no_double);
-
-BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- float cos[][3], int n,
- BMLoop **r_l, BMEdge *example);
-
-bool BM_face_split_edgenet(BMesh *bm, BMFace *f,
- BMEdge **edge_net, const int edge_net_len,
- BMFace ***r_face_arr, int *r_face_arr_len);
-
-BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
- const bool do_del, const bool join_faces, const bool kill_degenerate_faces);
-BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool kill_degenerate_faces);
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ BMLoop **r_l,
+ BMEdge *example, const bool no_double);
+
+BMFace *BM_face_split_n(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ float cos[][3], int n,
+BMLoop **r_l, BMEdge *example);
+
+bool BM_face_split_edgenet(
+ BMesh *bm, BMFace *f,
+ BMEdge **edge_net, const int edge_net_len,
+ BMFace ***r_face_arr, int *r_face_arr_len);
+
+BMEdge *BM_vert_collapse_faces(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
+ const bool do_del, const bool join_faces, const bool kill_degenerate_faces);
+BMEdge *BM_vert_collapse_edge(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces);
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent);
@@ -61,13 +66,16 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
bool BM_face_validate(BMFace *face, FILE *err);
-void BM_edge_calc_rotate(BMEdge *e, const bool ccw,
- BMLoop **r_l1, BMLoop **r_l2);
+void BM_edge_calc_rotate(
+ BMEdge *e, const bool ccw,
+ BMLoop **r_l1, BMLoop **r_l2);
bool BM_edge_rotate_check(BMEdge *e);
-bool BM_edge_rotate_check_degenerate(BMEdge *e,
- BMLoop *l1, BMLoop *l2);
-bool BM_edge_rotate_check_beauty(BMEdge *e,
- BMLoop *l1, BMLoop *l2);
+bool BM_edge_rotate_check_degenerate(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2);
+bool BM_edge_rotate_check_beauty(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2);
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
/* flags for BM_edge_rotate */
@@ -81,5 +89,7 @@ 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);
#endif /* __BMESH_MODS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index d0679b9919a..687fb62795f 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -160,6 +160,28 @@ static BMOpDefine bmo_recalc_face_normals_def = {
};
/*
+ * Planar Faces.
+ *
+ * Iteratively flatten faces.
+ */
+static BMOpDefine bmo_planar_faces_def = {
+ "planar_faces",
+ /* slots_in */
+ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input geometry. */
+ {"iterations", BMO_OP_SLOT_INT},
+ {"factor", BMO_OP_SLOT_FLT}, /* planar factor */
+ {{'\0'}},
+ },
+ /* slots_out */
+ {{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* output slot, computed boundary geometry. */
+ {{'\0'}},
+ },
+ bmo_planar_faces_exec,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
+};
+
+/*
* Region Extend.
*
* used to implement the select more/less tools.
@@ -359,6 +381,7 @@ static BMOpDefine bmo_collapse_def = {
"collapse",
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */
+ {"uvs", BMO_OP_SLOT_BOOL}, /* also collapse UVs and such */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -486,17 +509,19 @@ static BMOpDefine bmo_create_vert_def = {
* Join Triangles.
*
* Tries to intelligently join triangles according
- * to various settings and stuff.
+ * to angle threshold and delimiters.
*/
static BMOpDefine bmo_join_triangles_def = {
"join_triangles",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input geometry. */
+ {"cmp_seam", BMO_OP_SLOT_BOOL},
{"cmp_sharp", BMO_OP_SLOT_BOOL},
{"cmp_uvs", BMO_OP_SLOT_BOOL},
{"cmp_vcols", BMO_OP_SLOT_BOOL},
{"cmp_materials", BMO_OP_SLOT_BOOL},
- {"limit", BMO_OP_SLOT_FLT},
+ {"angle_face_threshold", BMO_OP_SLOT_FLT},
+ {"angle_shape_threshold", BMO_OP_SLOT_FLT},
{{'\0'}},
},
/* slots_out */
@@ -1841,6 +1866,27 @@ static BMOpDefine bmo_inset_region_def = {
};
/*
+ * Edgeloop Offset.
+ *
+ * Creates edge loops based on simple edge-outset method.
+ */
+static BMOpDefine bmo_offset_edgeloops_def = {
+ "offset_edgeloops",
+ /* slots_in */
+ {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input faces */
+ {"use_cap_endpoint", BMO_OP_SLOT_BOOL},
+ {{'\0'}},
+ },
+ /* slots_out */
+ {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output faces */
+ {{'\0'}},
+ },
+ bmo_offset_edgeloops_exec,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
+};
+
+/*
* Wire Frame.
*
* Makes a wire-frame copy of faces.
@@ -1996,6 +2042,7 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_duplicate_def,
&bmo_holes_fill_def,
&bmo_face_attribute_fill_def,
+ &bmo_offset_edgeloops_def,
&bmo_edgeloop_fill_def,
&bmo_edgenet_fill_def,
&bmo_edgenet_prepare_def,
@@ -2015,6 +2062,7 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_pointmerge_facedata_def,
&bmo_poke_def,
&bmo_recalc_face_normals_def,
+ &bmo_planar_faces_def,
&bmo_region_extend_def,
&bmo_remove_doubles_def,
&bmo_reverse_colors_def,
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index d966d882c67..14e9bf81be7 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -273,9 +273,10 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
(op_dst)->slots_dst, slot_name_dst, \
(op_dst)->arena)
-void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- struct MemArena *arena_dst);
+void _bmo_slot_copy(
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ struct MemArena *arena_dst);
/* del "context" slot values, used for operator too */
enum {
@@ -301,6 +302,8 @@ typedef enum {
BMO_DELIM_NORMAL = 1 << 0,
BMO_DELIM_MATERIAL = 1 << 1,
BMO_DELIM_SEAM = 1 << 2,
+ BMO_DELIM_SHARP = 1 << 3,
+ BMO_DELIM_UV = 1 << 4,
} BMO_Delimit;
void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
@@ -335,11 +338,12 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
-void BMO_mesh_selected_remap(BMesh *bm,
- BMOpSlot *slot_vert_map,
- BMOpSlot *slot_edge_map,
- BMOpSlot *slot_face_map,
- const bool check_select);
+void BMO_mesh_selected_remap(
+ BMesh *bm,
+ BMOpSlot *slot_vert_map,
+ BMOpSlot *slot_edge_map,
+ BMOpSlot *slot_face_map,
+ const bool check_select);
/* copies the values from another slot to the end of the output slot */
#define BMO_slot_buffer_append(op_src, slots_src, slot_name_src, \
@@ -347,53 +351,62 @@ void BMO_mesh_selected_remap(BMesh *bm,
_bmo_slot_buffer_append((op_src)->slots_src, slot_name_src, \
(op_dst)->slots_dst, slot_name_dst, \
(op_dst)->arena)
-void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- struct MemArena *arena_dst);
+void _bmo_slot_buffer_append(
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ struct MemArena *arena_dst);
/* puts every element of type 'type' (which is a bitmask) with tool
* flag 'flag', into a slot. */
-void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_from_enabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* puts every element of type 'type' (which is a bitmask) without tool
* flag 'flag', into a slot. */
-void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_from_disabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* tool-flags all elements inside an element slot array with flag flag. */
-void BMO_slot_buffer_flag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_flag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* clears tool-flag flag from all elements inside a slot array. */
-void BMO_slot_buffer_flag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_flag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* tool-flags all elements inside an element slot array with flag flag. */
-void BMO_slot_buffer_hflag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush);
+void BMO_slot_buffer_hflag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush);
/* clears tool-flag flag from all elements inside a slot array. */
-void BMO_slot_buffer_hflag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush);
+void BMO_slot_buffer_hflag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush);
/* puts every element of type 'type' (which is a bitmask) with header
* flag 'flag', into a slot. note: ignores hidden elements
* (e.g. elements with header flag BM_ELEM_HIDDEN set).*/
-void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag);
+void BMO_slot_buffer_from_enabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag);
/* puts every element of type 'type' (which is a bitmask) without
* header flag 'flag', into a slot. note: ignores hidden elements
* (e.g. elements with header flag BM_ELEM_HIDDEN set).*/
-void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag);
+void BMO_slot_buffer_from_disabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag);
void BMO_slot_buffer_from_array(BMOperator *op, BMOpSlot *slot, BMHeader **ele_buffer, int ele_buffer_len);
@@ -405,19 +418,23 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot);
int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, const void *data);
+void BMO_slot_map_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, const void *data);
/* flags all elements in a mapping. note that the mapping must only have
* bmesh elements in it.*/
-void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char hflag, const short oflag);
+void BMO_slot_map_to_flag(
+ BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char hflag, const short oflag);
-void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const int len);
+void *BMO_slot_buffer_alloc(
+ BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const int len);
-void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char htype);
+void BMO_slot_buffer_from_all(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char htype);
/**
* This part of the API is used to iterate over element buffer or
@@ -466,9 +483,10 @@ typedef struct BMOIter {
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void *BMO_iter_new(BMOIter *iter,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char restrictmask);
+void *BMO_iter_new(
+ BMOIter *iter,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char restrictmask);
void *BMO_iter_step(BMOIter *iter);
void **BMO_iter_map_value_p(BMOIter *iter);
@@ -483,8 +501,10 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter))
-/******************* Inlined Functions********************/
-typedef void (*opexec)(BMesh *bm, BMOperator *op);
+#define BMO_ITER_INDEX(ele, iter, slot_args, slot_name, restrict_flag, i_) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_new(iter, slot_args, slot_name, restrict_flag), i_ = 0; \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++)
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
index 2b78b775723..4f995e08b9c 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
@@ -38,55 +38,67 @@
* ghash or a mapping slot to do it. */
/* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
return oflags[bm->stackdepth - 1].f & oflag;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
return (oflags[bm->stackdepth - 1].f & oflag) != 0;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f |= oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f &= (short)~oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val)
{
if (val) oflags[bm->stackdepth - 1].f |= oflag;
else oflags[bm->stackdepth - 1].f &= (short)~oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f ^= oflag;
}
-BLI_INLINE void BMO_slot_map_int_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const int val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_int_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const int val)
{
union { void *ptr; int val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
}
-BLI_INLINE void BMO_slot_map_bool_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const bool val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_bool_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const bool val)
{
union { void *ptr; bool val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
}
-BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const float val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_float_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const float val)
{
union { void *ptr; float val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
@@ -99,15 +111,19 @@ BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot,
* do NOT use these for non-operator-api-allocated memory! instead
* use BMO_slot_map_data_get and BMO_slot_map_insert, which copies the data. */
-BLI_INLINE void BMO_slot_map_ptr_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, void *val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_ptr_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, void *val)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL);
BMO_slot_map_insert(op, slot, element, val);
}
-BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, void *val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_elem_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, void *val)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_ELEM);
BMO_slot_map_insert(op, slot, element, val);
@@ -115,25 +131,30 @@ BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot,
/* no values */
-BLI_INLINE void BMO_slot_map_empty_insert(BMOperator *op, BMOpSlot *slot,
- const void *element)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_empty_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_EMPTY);
BMO_slot_map_insert(op, slot, element, NULL);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BMO_slot_map_contains(BMOpSlot *slot, const void *element)
{
BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
return BLI_ghash_haskey(slot->data.ghash, element);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void **BMO_slot_map_data_get(BMOpSlot *slot, const void *element)
{
return BLI_ghash_lookup_p(slot->data.ghash, element);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE float BMO_slot_map_float_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -148,6 +169,7 @@ BLI_INLINE float BMO_slot_map_float_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE int BMO_slot_map_int_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -162,6 +184,7 @@ BLI_INLINE int BMO_slot_map_int_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BMO_slot_map_bool_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -176,6 +199,7 @@ BLI_INLINE bool BMO_slot_map_bool_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BMO_slot_map_ptr_get(BMOpSlot *slot, const void *element)
{
void **val = BMO_slot_map_data_get(slot, element);
@@ -185,6 +209,7 @@ BLI_INLINE void *BMO_slot_map_ptr_get(BMOpSlot *slot, const void *element)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BMO_slot_map_elem_get(BMOpSlot *slot, const void *element)
{
void **val = (void **) BMO_slot_map_data_get(slot, element);
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index ba154b04838..dda1f2fe30a 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -281,9 +281,10 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
* define used.
* Copies data from one slot to another.
*/
-void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- struct MemArena *arena_dst)
+void _bmo_slot_copy(
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ struct MemArena *arena_dst)
{
BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
@@ -543,8 +544,9 @@ void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
*
*/
-static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
- const bool test_for_enabled)
+static int bmo_mesh_flag_count(
+ BMesh *bm, const char htype, const short oflag,
+ const bool test_for_enabled)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -602,11 +604,12 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char hty
}
}
-void BMO_mesh_selected_remap(BMesh *bm,
- BMOpSlot *slot_vert_map,
- BMOpSlot *slot_edge_map,
- BMOpSlot *slot_face_map,
- const bool check_select)
+void BMO_mesh_selected_remap(
+ BMesh *bm,
+ BMOpSlot *slot_vert_map,
+ BMOpSlot *slot_edge_map,
+ BMOpSlot *slot_face_map,
+ const bool check_select)
{
if (bm->selected.first) {
BMEditSelection *ese, *ese_next;
@@ -663,8 +666,9 @@ int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
/* inserts a key/value mapping into a mapping slot. note that it copies the
* value, it doesn't store a reference to it. */
-void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, const void *data)
+void BMO_slot_map_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, const void *data)
{
(void) op; /* Ignored in release builds. */
@@ -717,8 +721,9 @@ void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
}
#endif
-void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_map_to_flag(
+ BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
GHashIterator gh_iter;
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
@@ -759,8 +764,9 @@ void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS]
*
* Copies all elements of a certain type into an operator slot.
*/
-void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char htype)
+void BMO_slot_buffer_from_all(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char htype)
{
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
@@ -809,9 +815,10 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_
* Copies elements of a certain type, which have a certain header flag
* enabled/disabled into a slot for an operator.
*/
-static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag,
- const bool test_for_enabled)
+static void bmo_slot_buffer_from_hflag(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag,
+ const bool test_for_enabled)
{
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
@@ -872,16 +879,18 @@ static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_
}
}
-void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag)
+void BMO_slot_buffer_from_enabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag)
{
bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, true);
}
-void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag)
+void BMO_slot_buffer_from_disabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag)
{
bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, false);
}
@@ -927,9 +936,10 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
/**
* Copies the values from another slot to the end of the output slot.
*/
-void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- struct MemArena *arena_dst)
+void _bmo_slot_buffer_append(
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ struct MemArena *arena_dst)
{
BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
@@ -964,10 +974,11 @@ void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const cha
* Copies elements of a certain type, which have a certain flag set
* into an output slot for an operator.
*/
-static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag,
- const bool test_for_enabled)
+static void bmo_slot_buffer_from_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag,
+ const bool test_for_enabled)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
int totelement, i = 0;
@@ -1026,16 +1037,18 @@ static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
}
}
-void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_from_enabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, true);
}
-void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_from_disabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
}
@@ -1046,9 +1059,10 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
* Header Flags elements in a slots buffer, automatically
* using the selection API where appropriate.
*/
-void BMO_slot_buffer_hflag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush)
+void BMO_slot_buffer_hflag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMElem **data = (BMElem **)slot->data.buf;
@@ -1082,9 +1096,10 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
* Removes flags from elements in a slots buffer, automatically
* using the selection API where appropriate.
*/
-void BMO_slot_buffer_hflag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush)
+void BMO_slot_buffer_hflag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMElem **data = (BMElem **)slot->data.buf;
@@ -1116,9 +1131,10 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
*
* Flags elements in a slots buffer
*/
-void BMO_slot_buffer_flag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_flag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMHeader **data = slot->data.p;
@@ -1140,9 +1156,10 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
*
* Removes flags from elements in a slots buffer
*/
-void BMO_slot_buffer_flag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_flag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMHeader **data = (BMHeader **)slot->data.buf;
@@ -1394,9 +1411,10 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
* \param restrictmask restricts the iteration to certain element types
* (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
* over an element buffer (not a mapping). */
-void *BMO_iter_new(BMOIter *iter,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char restrictmask)
+void *BMO_iter_new(
+ BMOIter *iter,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char restrictmask)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index f39fe29b596..d9961e589da 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -46,6 +46,7 @@ enum {
SUBD_FALLOFF_ROOT,
SUBD_FALLOFF_SHARP,
SUBD_FALLOFF_LIN,
+ SUBD_FALLOFF_INVSQUARE = 7, /* matching PROP_INVSQUARE */
};
enum {
@@ -130,14 +131,15 @@ extern const BMOpDefine *bmo_opdefines[];
extern const int bmo_opdefines_total;
/*------specific operator helper functions-------*/
-void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag,
- const float smooth, const short smooth_falloff, const bool use_smooth_even,
- const float fractal, const float along_normal,
- const int numcuts,
- const int seltype, const int cornertype,
- const short use_single_edge, const short use_grid_fill,
- const short use_only_quads,
- const int seed);
+void BM_mesh_esubdivide(
+ BMesh *bm, const char edge_hflag,
+ const float smooth, const short smooth_falloff, const bool use_smooth_even,
+ const float fractal, const float along_normal,
+ const int numcuts,
+ const int seltype, const int cornertype,
+ const short use_single_edge, const short use_grid_fill,
+ const short use_only_quads,
+ const int seed);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 979f7d2640a..5548ee7c361 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -82,6 +82,8 @@ void bmo_pointmerge_exec(BMesh *bm, BMOperator *op);
void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op);
void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op);
void bmo_poke_exec(BMesh *bm, BMOperator *op);
+void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op);
+void bmo_planar_faces_exec(BMesh *bm, BMOperator *op);
void bmo_region_extend_exec(BMesh *bm, BMOperator *op);
void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op);
void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index bc06ba2c9b1..d2d31d6a562 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -102,8 +102,9 @@ static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
* Same as #calc_poly_normal and #bm_face_calc_poly_normal
* but takes an array of vertex locations.
*/
-static float bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[3],
- float const (*vertexCos)[3])
+static float bm_face_calc_poly_normal_vertex_cos(
+ BMFace *f, float r_no[3],
+ float const (*vertexCos)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -127,8 +128,9 @@ static float bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[3],
/**
* \brief COMPUTE POLY CENTER (BMFace)
*/
-static void bm_face_calc_poly_center_mean_vertex_cos(BMFace *f, float r_cent[3],
- float const (*vertexCos)[3])
+static void bm_face_calc_poly_center_mean_vertex_cos(
+ BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -548,8 +550,9 @@ void BM_face_normal_update(BMFace *f)
}
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
-float BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
- float const (*vertexCos)[3])
+float BM_face_calc_normal_vcos(
+ BMesh *bm, BMFace *f, float r_no[3],
+ float const (*vertexCos)[3])
{
BMLoop *l;
@@ -607,8 +610,9 @@ float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3])
}
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
-void BM_face_calc_center_mean_vcos(BMesh *bm, BMFace *f, float r_cent[3],
- float const (*vertexCos)[3])
+void BM_face_calc_center_mean_vcos(
+ BMesh *bm, BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3])
{
/* must have valid index data */
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 9980b59a298..582b4248c7d 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -36,16 +36,18 @@ void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_loopt
void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
-float BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
- float const (*vertexCos)[3]) ATTR_NONNULL();
+float BM_face_calc_normal_vcos(
+ BMesh *bm, BMFace *f, float r_no[3],
+ float const (*vertexCos)[3]) ATTR_NONNULL();
float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_area(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_face_calc_perimeter(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_face_calc_plane(BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_center_bounds(BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean(BMFace *f, float center[3]) ATTR_NONNULL();
-void BM_face_calc_center_mean_vcos(BMesh *bm, BMFace *f, float r_cent[3],
- float const (*vertexCos)[3]) ATTR_NONNULL();
+void BM_face_calc_center_mean_vcos(
+ BMesh *bm, BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3]) ATTR_NONNULL();
void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 102a677943b..814015a2a74 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -54,6 +54,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
+int bmesh_disk_count_ex(const BMVert *v, const int count_max);
int bmesh_disk_count(const BMVert *v);
/**
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 7c557cb1343..09284ea3549 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -38,6 +38,8 @@
#include "BLI_linklist.h"
#include "BLI_stackdefines.h"
+#include "BKE_customdata.h"
+
#include "bmesh.h"
#include "intern/bmesh_private.h"
@@ -255,6 +257,36 @@ BMFace *BM_vert_pair_share_face_by_len(
return f_cur;
}
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent)
+{
+ BMLoop *l_cur_a = NULL, *l_cur_b = NULL;
+ BMFace *f_cur = NULL;
+
+ if (e_a->l && e_b->l) {
+ BMIter iter;
+ BMLoop *l_a, *l_b;
+
+ BM_ITER_ELEM (l_a, &iter, e_a, BM_LOOPS_OF_EDGE) {
+ if ((f_cur == NULL) || (l_a->f->len < f_cur->len)) {
+ l_b = BM_face_edge_share_loop(l_a->f, e_b);
+ if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
+ f_cur = l_a->f;
+ l_cur_a = l_a;
+ l_cur_b = l_b;
+ }
+ }
+ }
+ }
+
+ *r_l_a = l_cur_a;
+ *r_l_b = l_cur_b;
+
+ return f_cur;
+}
+
static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
{
float no[2][3];
@@ -501,10 +533,10 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
/**
* Returns whether or not a given edge is part of a given face.
*/
-bool BM_edge_in_face(BMEdge *e, BMFace *f)
+bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
{
if (e->l) {
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
@@ -750,6 +782,11 @@ int BM_vert_edge_count(const BMVert *v)
return bmesh_disk_count(v);
}
+int BM_vert_edge_count_ex(const BMVert *v, const int count_max)
+{
+ return bmesh_disk_count_ex(v, count_max);
+}
+
int BM_vert_edge_count_nonwire(const BMVert *v)
{
int count = 0;
@@ -770,13 +807,30 @@ int BM_edge_face_count(const BMEdge *e)
int count = 0;
if (e->l) {
- BMLoop *l_iter;
- BMLoop *l_first;
+ BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
+ do {
+ count++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ return count;
+}
+
+int BM_edge_face_count_ex(const BMEdge *e, const int count_max)
+{
+ int count = 0;
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = e->l;
do {
count++;
+ if (count == count_max) {
+ break;
+ }
} while ((l_iter = l_iter->radial_next) != l_first);
}
@@ -792,6 +846,21 @@ int BM_vert_face_count(const BMVert *v)
return bmesh_disk_facevert_count(v);
}
+int BM_vert_face_count_ex(const BMVert *v, int count_max)
+{
+ return bmesh_disk_facevert_count_ex(v, count_max);
+}
+
+/**
+ * Return true if the vertex is connected to _any_ faces.
+ *
+ * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
+ */
+bool BM_vert_face_check(BMVert *v)
+{
+ return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
+}
+
/**
* Tests whether or not the vertex is part of a wire edge.
* (ie: has no faces attached to it)
@@ -824,9 +893,9 @@ bool BM_vert_is_wire(const BMVert *v)
*/
bool BM_vert_is_manifold(const BMVert *v)
{
- BMEdge *e, *e_old;
- BMLoop *l;
- int len, count, flag;
+ BMEdge *e_iter, *e_first, *e_prev;
+ BMLoop *l_iter, *l_first;
+ int loop_num = 0, loop_num_region = 0, boundary_num = 0;
if (v->e == NULL) {
/* loose vert */
@@ -834,50 +903,150 @@ bool BM_vert_is_manifold(const BMVert *v)
}
/* count edges while looking for non-manifold edges */
- len = 0;
- e_old = e = v->e;
+ e_first = e_iter = v->e;
+ l_first = e_iter->l ? e_iter->l : NULL;
do {
/* loose edge or edge shared by more than two faces,
* edges with 1 face user are OK, otherwise we could
* use BM_edge_is_manifold() here */
- if (e->l == NULL || bmesh_radial_length(e->l) > 2) {
+ if (e_iter->l == NULL || (e_iter->l != e_iter->l->radial_next->radial_next)) {
return false;
}
- len++;
- } while ((e = bmesh_disk_edge_next(e, v)) != e_old);
-
- count = 1;
- flag = 1;
- e = NULL;
- e_old = v->e;
- l = e_old->l;
- while (e != e_old) {
- l = (l->v == v) ? l->prev : l->next;
- e = l->e;
- count++; /* count the edges */
-
- if (flag && l->radial_next == l) {
- /* we've hit the edge of an open mesh, reset once */
- flag = 0;
- count = 1;
- e_old = e;
- e = NULL;
- l = e_old->l;
- }
- else if (l->radial_next == l) {
- /* break the loop */
- e = e_old;
+
+ /* count radial loops */
+ if (e_iter->l->v == v) {
+ loop_num += 1;
+ }
+
+ if (!BM_edge_is_boundary(e_iter)) {
+ /* non boundary check opposite loop */
+ if (e_iter->l->radial_next->v == v) {
+ loop_num += 1;
+ }
}
else {
- l = l->radial_next;
+ /* start at the boundary */
+ l_first = e_iter->l;
+ boundary_num += 1;
+ /* >2 boundaries cant be manifold */
+ if (boundary_num == 3) {
+ return false;
+ }
}
- }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- if (count < len) {
- /* vert shared by multiple regions */
- return false;
+ e_first = l_first->e;
+ l_first = (l_first->v == v) ? l_first : l_first->next;
+ BLI_assert(l_first->v == v);
+
+ l_iter = l_first;
+ e_prev = e_first;
+
+ do {
+ loop_num_region += 1;
+ } while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != NULL));
+
+ return (loop_num == loop_num_region);
+}
+
+#define LOOP_VISIT _FLAG_WALK
+#define EDGE_VISIT _FLAG_WALK
+
+static int bm_loop_region_count__recursive(BMEdge *e, BMVert *v)
+{
+ BMLoop *l_iter, *l_first;
+ int count = 0;
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v) {
+ BMEdge *e_other = l_iter->prev->e;
+ if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ BM_ELEM_API_FLAG_ENABLE(l_iter, LOOP_VISIT);
+ count += 1;
+ }
+ if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+ count += bm_loop_region_count__recursive(e_other, v);
+ }
+ }
+ else if (l_iter->next->v == v) {
+ BMEdge *e_other = l_iter->next->e;
+ if (!BM_ELEM_API_FLAG_TEST(l_iter->next, LOOP_VISIT)) {
+ BM_ELEM_API_FLAG_ENABLE(l_iter->next, LOOP_VISIT);
+ count += 1;
+ }
+ if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+ count += bm_loop_region_count__recursive(e_other, v);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+
+ return count;
+}
+
+static int bm_loop_region_count__clear(BMLoop *l)
+{
+ int count = 0;
+ BMEdge *e_iter, *e_first;
+
+ /* clear flags */
+ e_iter = e_first = l->e;
+ do {
+ BM_ELEM_API_FLAG_DISABLE(e_iter, EDGE_VISIT);
+ if (e_iter->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_iter->l;
+ do {
+ if (l_iter->v == l->v) {
+ BM_ELEM_API_FLAG_DISABLE(l_iter, LOOP_VISIT);
+ count += 1;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
+
+ return count;
+}
+
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
+int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total)
+{
+ const int count = bm_loop_region_count__recursive(l->e, l->v);
+ const int count_total = bm_loop_region_count__clear(l);
+ if (r_loop_total) {
+ *r_loop_total = count_total;
}
+ return count;
+}
+
+#undef LOOP_VISIT
+#undef EDGE_VISIT
+
+int BM_loop_region_loops_count(BMLoop *l)
+{
+ return BM_loop_region_loops_count_ex(l, NULL);
+}
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
+bool BM_vert_is_manifold_region(const BMVert *v)
+{
+ BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
+ if (l_first) {
+ int count, count_total;
+ count = BM_loop_region_loops_count_ex(l_first, &count_total);
+ return (count == count_total);
+ }
return true;
}
@@ -902,6 +1071,53 @@ bool BM_edge_is_convex(const BMEdge *e)
return true;
}
+/**
+ * \return true when loop customdata is contiguous.
+ */
+bool BM_edge_is_contiguous_loop_cd(
+ const BMEdge *e,
+ const int cd_loop_type, const int cd_loop_offset)
+{
+ BLI_assert(cd_loop_offset != -1);
+
+ if (e->l && e->l->radial_next != e->l) {
+ const BMLoop *l_base_v1 = e->l;
+ const BMLoop *l_base_v2 = e->l->next;
+ const void *l_base_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_base_v1, cd_loop_offset);
+ const void *l_base_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_base_v2, cd_loop_offset);
+ const BMLoop *l_iter = e->l->radial_next;
+ do {
+ const BMLoop *l_iter_v1;
+ const BMLoop *l_iter_v2;
+ const void *l_iter_cd_v1;
+ const void *l_iter_cd_v2;
+
+ if (l_iter->v == l_base_v1->v) {
+ l_iter_v1 = l_iter;
+ l_iter_v2 = l_iter->next;
+ }
+ else {
+ l_iter_v1 = l_iter->next;
+ l_iter_v2 = l_iter;
+ }
+ BLI_assert((l_iter_v1->v == l_base_v1->v) &&
+ (l_iter_v2->v == l_base_v2->v));
+
+ l_iter_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_iter_v1, cd_loop_offset);
+ l_iter_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_iter_v2, cd_loop_offset);
+
+
+ if ((CustomData_data_equals(cd_loop_type, l_base_cd_v1, l_iter_cd_v1) == 0) ||
+ (CustomData_data_equals(cd_loop_type, l_base_cd_v2, l_iter_cd_v2) == 0))
+ {
+ return false;
+ }
+
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ return true;
+}
+
bool BM_vert_is_boundary(const BMVert *v)
{
if (v->e) {
@@ -1147,8 +1363,9 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
* \note This is in fact quite a simple check, mainly include this function so the intent is more obvious.
* We know these 2 verts will _always_ make up the loops edge
*/
-void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
- const BMLoop *edge_loop)
+void BM_edge_ordered_verts_ex(
+ const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
+ const BMLoop *edge_loop)
{
BLI_assert(edge_loop->e == edge);
(void)edge; /* quiet warning in release build */
@@ -1162,6 +1379,46 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
}
/**
+ * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
+BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
+{
+ BMLoop *l_step = l->prev;
+
+ BLI_assert(!ELEM(l_stop, NULL, l));
+
+ while (UNLIKELY(len_squared_v3v3(l->v->co, l_step->v->co) < eps_sq)) {
+ l_step = l_step->prev;
+ BLI_assert(l_step != l);
+ if (UNLIKELY(l_step == l_stop)) {
+ return NULL;
+ }
+ }
+
+ return l_step;
+}
+
+/**
+ * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
+BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
+{
+ BMLoop *l_step = l->next;
+
+ BLI_assert(!ELEM(l_stop, NULL, l));
+
+ while (UNLIKELY(len_squared_v3v3(l->v->co, l_step->v->co) < eps_sq)) {
+ l_step = l_step->next;
+ BLI_assert(l_step != l);
+ if (UNLIKELY(l_step == l_stop)) {
+ return NULL;
+ }
+ }
+
+ return l_step;
+}
+
+/**
* Check if the loop is convex or concave
* (depends on face normal)
*/
@@ -1183,7 +1440,7 @@ bool BM_loop_is_convex(const BMLoop *l)
*
* \return angle in radians
*/
-float BM_loop_calc_face_angle(BMLoop *l)
+float BM_loop_calc_face_angle(const BMLoop *l)
{
return angle_v3v3v3(l->prev->v->co,
l->v->co,
@@ -1198,7 +1455,7 @@ float BM_loop_calc_face_angle(BMLoop *l)
* \param l The loop to calculate the normal at
* \param r_normal Resulting normal
*/
-void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3])
+void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
{
if (normal_tri_v3(r_normal,
l->prev->v->co,
@@ -1220,7 +1477,7 @@ void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3])
* \param l The loop to calculate the direction at
* \param r_dir Resulting direction
*/
-void BM_loop_calc_face_direction(BMLoop *l, float r_dir[3])
+void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
{
float v_prev[3];
float v_next[3];
@@ -1244,7 +1501,7 @@ void BM_loop_calc_face_direction(BMLoop *l, float r_dir[3])
* \param l The loop to calculate the tangent at
* \param r_tangent Resulting tangent
*/
-void BM_loop_calc_face_tangent(BMLoop *l, float r_tangent[3])
+void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
{
float v_prev[3];
float v_next[3];
@@ -1356,7 +1613,7 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
*
* \returns the angle in radians
*/
-float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback)
+float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
{
BMEdge *e1, *e2;
@@ -1378,7 +1635,7 @@ float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback)
}
}
-float BM_vert_calc_edge_angle(BMVert *v)
+float BM_vert_calc_edge_angle(const BMVert *v)
{
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
}
@@ -1387,14 +1644,14 @@ float BM_vert_calc_edge_angle(BMVert *v)
* \note this isn't optimal to run on an array of verts,
* see 'solidify_add_thickness' for a function which runs on an array.
*/
-float BM_vert_calc_shell_factor(BMVert *v)
+float BM_vert_calc_shell_factor(const BMVert *v)
{
BMIter iter;
BMLoop *l;
float accum_shell = 0.0f;
float accum_angle = 0.0f;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
const float face_angle = BM_loop_calc_face_angle(l);
accum_shell += shell_v3v3_normalized_to_dist(v->no, l->f->no) * face_angle;
accum_angle += face_angle;
@@ -1409,15 +1666,15 @@ float BM_vert_calc_shell_factor(BMVert *v)
}
/* alternate version of #BM_vert_calc_shell_factor which only
* uses 'hflag' faces, but falls back to all if none found. */
-float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hflag)
+float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
{
BMIter iter;
- BMLoop *l;
+ const BMLoop *l;
float accum_shell = 0.0f;
float accum_angle = 0.0f;
int tot_sel = 0, tot = 0;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
if (BM_elem_flag_test(l->f, hflag)) { /* <-- main difference to BM_vert_calc_shell_factor! */
const float face_angle = BM_loop_calc_face_angle(l);
accum_shell += shell_v3v3_normalized_to_dist(no, l->f->no) * face_angle;
@@ -1446,15 +1703,15 @@ float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hfla
* \note quite an obscure function.
* used in bmesh operators that have a relative scale options,
*/
-float BM_vert_calc_mean_tagged_edge_length(BMVert *v)
+float BM_vert_calc_mean_tagged_edge_length(const BMVert *v)
{
BMIter iter;
BMEdge *e;
int tot;
float length = 0.0f;
- BM_ITER_ELEM_INDEX (e, &iter, v, BM_EDGES_OF_VERT, tot) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ BM_ITER_ELEM_INDEX (e, &iter, (BMVert *)v, BM_EDGES_OF_VERT, tot) {
+ const BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
length += BM_edge_calc_length(e);
}
@@ -1600,85 +1857,59 @@ BMEdge *BM_edge_find_double(BMEdge *e)
*/
bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
{
- BMVert *v_search = varr[0]; /* we can search any of the verts in the array */
- BMIter liter;
- BMLoop *l_search;
-
-
-#if 0
- BM_ITER_ELEM (f, &viter, v_search, BM_FACES_OF_VERT) {
- if (f->len == len) {
- if (BM_verts_in_face(varr, len, f)) {
- if (r_existface) {
- *r_existface = f;
- }
- return true;
- }
- }
- }
-
- if (r_existface) {
- *r_existface = NULL;
- }
- return false;
-
-#else
-
- /* faster to do the flagging once, and inline */
- bool is_init = false;
- bool is_found = false;
- int i;
-
-
- BM_ITER_ELEM (l_search, &liter, v_search, BM_LOOPS_OF_VERT) {
- if (l_search->f->len == len) {
- if (is_init == false) {
- is_init = true;
- for (i = 0; i < len; i++) {
- BLI_assert(!BM_ELEM_API_FLAG_TEST(varr[i], _FLAG_OVERLAP));
- BM_ELEM_API_FLAG_ENABLE(varr[i], _FLAG_OVERLAP);
- }
- }
-
- is_found = true;
-
- {
- BMLoop *l_iter;
+ if (varr[0]->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = varr[0]->e;
- /* skip ourselves */
- l_iter = l_search->next;
+ /* would normally use BM_LOOPS_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ l_iter_radial = l_first_radial = e_iter->l;
do {
- if (!BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP)) {
- is_found = false;
- break;
+ if ((l_iter_radial->v == varr[0]) &&
+ (l_iter_radial->f->len == len))
+ {
+ /* the fist 2 verts match, now check the remaining (len - 2) faces do too
+ * winding isn't known, so check in both directions */
+ int i_walk = 2;
+
+ if (l_iter_radial->next->v == varr[1]) {
+ BMLoop *l_walk = l_iter_radial->next->next;
+ do {
+ if (l_walk->v != varr[i_walk]) {
+ break;
+ }
+ } while ((l_walk = l_walk->next), ++i_walk != len);
+ }
+ else if (l_iter_radial->prev->v == varr[1]) {
+ BMLoop *l_walk = l_iter_radial->prev->prev;
+ do {
+ if (l_walk->v != varr[i_walk]) {
+ break;
+ }
+ } while ((l_walk = l_walk->prev), ++i_walk != len);
+ }
+
+ if (i_walk == len) {
+ if (r_existface) {
+ *r_existface = l_iter_radial->f;
+ }
+ return true;
+ }
}
- } while ((l_iter = l_iter->next) != l_search);
- }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
- if (is_found) {
- if (r_existface) {
- *r_existface = l_search->f;
- }
- break;
}
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
}
- if (is_found == false) {
- if (r_existface) {
- *r_existface = NULL;
- }
- }
-
- if (is_init == true) {
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(varr[i], _FLAG_OVERLAP);
- }
+ if (r_existface) {
+ *r_existface = NULL;
}
-
- return is_found;
-#endif
+ return false;
}
@@ -1773,8 +2004,8 @@ bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
if (/* non-boundary edge */
BM_elem_flag_test(e, BM_ELEM_INTERNAL_TAG) == false &&
/* ...using boundary verts */
- BM_elem_flag_test(e->v1, BM_ELEM_INTERNAL_TAG) == true &&
- BM_elem_flag_test(e->v2, BM_ELEM_INTERNAL_TAG) == true)
+ BM_elem_flag_test(e->v1, BM_ELEM_INTERNAL_TAG) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_INTERNAL_TAG))
{
int tot_face_tag = 0;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
@@ -2117,9 +2348,10 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
* (having both set is supported too).
* \return The number of groups found.
*/
-int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test, const char htype_step)
+int BM_mesh_calc_face_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test, const char htype_step)
{
#ifdef DEBUG
int group_index_len = 1;
@@ -2274,9 +2506,10 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
* \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
* since we always walk over verts.
*/
-int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test)
+int BM_mesh_calc_edge_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test)
{
#ifdef DEBUG
int group_index_len = 1;
@@ -2405,6 +2638,9 @@ float bmesh_subd_falloff_calc(const int falloff, float val)
break;
case SUBD_FALLOFF_LIN:
break;
+ case SUBD_FALLOFF_INVSQUARE:
+ val = val * (2.0f - val);
+ break;
default:
BLI_assert(0);
break;
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 4ee5588ba0b..2b18a5c8641 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -31,7 +31,7 @@ bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNU
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_edge_in_face(BMEdge *e, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -64,32 +64,57 @@ BMFace *BM_vert_pair_share_face_by_angle(
BMLoop **r_l_a, BMLoop **r_l_b,
const bool allow_adjacent) ATTR_NONNULL();
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent) ATTR_NONNULL();
+
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == n)
+#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == (n) + 1)
+int BM_vert_edge_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_ex(e, (n) + 1) == n)
+#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_ex(e, (n) + 1) == (n) + 1)
+int BM_edge_face_count_ex(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_ex(v, (n) + 1) == n)
+#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_ex(v, (n) + 1) == (n) + 1)
+int BM_vert_face_count_ex(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
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_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_is_contiguous_loop_cd(
+ const BMEdge *e,
+ const int cd_loop_type, const int cd_loop_offset)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_loop_calc_face_angle(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]) ATTR_NONNULL();
-void BM_loop_calc_face_direction(BMLoop *l, float r_normal[3]);
-void BM_loop_calc_face_tangent(BMLoop *l, float r_tangent[3]);
+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();
+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]);
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -97,11 +122,11 @@ float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]) ATTR_NONNULL();
-float BM_vert_calc_edge_angle(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_shell_factor(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_mean_tagged_edge_length(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_mean_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -132,8 +157,9 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT AT
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
-void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
- const BMLoop *edge_loop) ATTR_NONNULL();
+void BM_edge_ordered_verts_ex(
+ const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
+ const BMLoop *edge_loop) ATTR_NONNULL();
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -147,12 +173,16 @@ bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNU
float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test, const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
-int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+int BM_mesh_calc_face_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test, const char htype_step)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+int BM_mesh_calc_edge_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
/* not really any good place to put this */
float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h
index 1ca56beb746..430ba10fb42 100644
--- a/source/blender/bmesh/intern/bmesh_queries_inline.h
+++ b/source/blender/bmesh/intern/bmesh_queries_inline.h
@@ -30,6 +30,7 @@
* Returns whether or not a given vertex is
* is part of a given edge.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v)
{
return (ELEM(v, e->v1, e->v2));
@@ -38,6 +39,7 @@ BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v)
/**
* Returns whether or not a given edge is part of a given loop.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l)
{
return (l->e == e || l->prev->e == e);
@@ -47,6 +49,7 @@ BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l)
* Returns whether or not two vertices are in
* a given edge
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3)
BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e)
{
return ((e->v1 == v1 && e->v2 == v2) ||
@@ -57,6 +60,7 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdg
* Given a edge and one of its vertices, returns
* the other vertex.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v)
{
if (e->v1 == v) {
@@ -72,6 +76,7 @@ BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v)
* Tests whether or not the edge is part of a wire.
* (ie: has no faces attached to it)
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e)
{
return (e->l == NULL);
@@ -83,6 +88,7 @@ BLI_INLINE bool BM_edge_is_wire(const BMEdge *e)
*/
#if 1 /* fast path for checking manifold */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -100,6 +106,7 @@ BLI_INLINE int BM_edge_is_manifold(BMEdge *e)
* Tests that the edge is manifold and
* that both its faces point the same way.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -115,6 +122,7 @@ BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e)
*/
#if 1 /* fast path for checking boundary */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -130,6 +138,7 @@ BLI_INLINE int BM_edge_is_boundary(BMEdge *e)
/**
* Tests whether one loop is next to another within the same face.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
{
BLI_assert(l_a->f == l_b->f);
@@ -140,6 +149,7 @@ BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
/**
* Check if we have a single wire edge user.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_vert_is_wire_endpoint(const BMVert *v)
{
const BMEdge *e = v->e;
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index 3e8002c0192..cb302139a4c 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -40,19 +40,56 @@
* MISC utility functions.
*/
-bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
+void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
{
- if (e->v1 == v_orig) {
- e->v1 = v_new;
+ if (e->v1 == v_src) {
+ e->v1 = v_dst;
e->v1_disk_link.next = e->v1_disk_link.prev = NULL;
- return true;
}
- else if (e->v2 == v_orig) {
- e->v2 = v_new;
+ else if (e->v2 == v_src) {
+ e->v2 = v_dst;
e->v2_disk_link.next = e->v2_disk_link.prev = NULL;
- return true;
}
- return false;
+ else {
+ BLI_assert(0);
+ }
+}
+
+/**
+ * Handles all connected data, use with care.
+ *
+ * Assumes caller has setup correct state before the swap is done.
+ */
+void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ /* swap out loops */
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v_src) {
+ l_iter->v = v_dst;
+ }
+ else if (l_iter->next->v == v_src) {
+ l_iter->next->v = v_dst;
+ }
+ else {
+ BLI_assert(l_iter->prev->v != v_src);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ /* swap out edges */
+ bmesh_disk_vert_replace(e, v_dst, v_src);
+}
+
+void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ BLI_assert(e->v1 == v_src || e->v2 == v_src);
+ bmesh_disk_edge_remove(e, v_src); /* remove e from tv's disk cycle */
+ bmesh_disk_vert_swap(e, v_dst, v_src); /* swap out tv for v_new in e */
+ bmesh_disk_edge_append(e, v_dst); /* add e to v_dst's disk cycle */
+ BLI_assert(e->v1 != e->v2);
}
/**
@@ -88,6 +125,7 @@ bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
* the disk cycle has no problems dealing with non-manifold conditions involving faces.
*
* Functions relating to this cycle:
+ * - #bmesh_disk_vert_replace
* - #bmesh_disk_edge_append
* - #bmesh_disk_edge_remove
* - #bmesh_disk_edge_next
@@ -206,13 +244,29 @@ int bmesh_disk_count(const BMVert *v)
return count;
}
+int bmesh_disk_count_ex(const BMVert *v, const int count_max)
+{
+ int count = 0;
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v->e;
+ do {
+ count++;
+ if (count == count_max) {
+ break;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return count;
+}
+
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
{
BMEdge *e_iter;
if (!BM_vert_in_edge(e, v))
return false;
- if (bmesh_disk_count(v) != len || len == 0)
+ if (bmesh_disk_count_ex(v, len + 1) != len || len == 0)
return false;
e_iter = e;
@@ -236,9 +290,9 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
+ int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
- int count = 0;
/* first, loop around edge */
e_first = e_iter = v->e;
@@ -247,11 +301,29 @@ int bmesh_disk_facevert_count(const BMVert *v)
count += bmesh_radial_facevert_count(e_iter->l, v);
}
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- return count;
}
- else {
- return 0;
+ return count;
+}
+
+int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
+{
+ /* is there an edge on this vert at all */
+ int count = 0;
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+
+ /* first, loop around edge */
+ e_first = e_iter = v->e;
+ do {
+ if (e_iter->l) {
+ count += bmesh_radial_facevert_count_ex(e_iter->l, v, count_max - count);
+ if (count == count_max) {
+ break;
+ }
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
+ return count;
}
/**
@@ -456,6 +528,23 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
return count;
}
+int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max)
+{
+ const BMLoop *l_iter;
+ int count = 0;
+ l_iter = l;
+ do {
+ if (l_iter->v == v) {
+ count++;
+ if (count == count_max) {
+ break;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l);
+
+ return count;
+}
+
/**
* \brief RADIAL CHECK FACE VERT
*
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 29868194bbf..07f94796bb2 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -49,6 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) A
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -60,6 +61,7 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
+int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -68,7 +70,9 @@ BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_W
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
-bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new) ATTR_NONNULL();
+void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure_inline.h b/source/blender/bmesh/intern/bmesh_structure_inline.h
index 5b7e890f5ea..64292194ae7 100644
--- a/source/blender/bmesh/intern/bmesh_structure_inline.h
+++ b/source/blender/bmesh/intern/bmesh_structure_inline.h
@@ -27,6 +27,7 @@
#ifndef __BMESH_STRUCTURE_INLINE_H__
#define __BMESH_STRUCTURE_INLINE_H__
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(const BMEdge *e, const BMVert *v)
{
BLI_assert(BM_vert_in_edge(e, v));
@@ -40,6 +41,7 @@ BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(const BMEdge *e, const BMV
*
* \return Pointer to the next edge in the disk cycle for the vertex v.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
@@ -49,6 +51,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
@@ -58,11 +61,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v)
{
return BM_DISK_EDGE_NEXT(e, v);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v)
{
return BM_DISK_EDGE_PREV(e, v);
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index 20b56632099..d16eb572540 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -74,10 +74,11 @@ void *BMW_begin(BMWalker *walker, void *start)
* a given type. The elements visited are filtered
* by the bitmask 'searchmask'.
*/
-void BMW_init(BMWalker *walker, BMesh *bm, int type,
- short mask_vert, short mask_edge, short mask_face,
- BMWFlag flag,
- int layer)
+void BMW_init(
+ BMWalker *walker, BMesh *bm, int type,
+ short mask_vert, short mask_edge, short mask_face,
+ BMWFlag flag,
+ int layer)
{
memset(walker, 0, sizeof(BMWalker));
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index d551ea9fba9..f5a801a31c3 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -76,10 +76,11 @@ typedef struct BMWalker {
/* initialize a walker. searchmask restricts some (not all) walkers to
* elements with a specific tool flag set. flags is specific to each walker.*/
-void BMW_init(struct BMWalker *walker, BMesh *bm, int type,
- short mask_vert, short mask_edge, short mask_face,
- BMWFlag flag,
- int layer);
+void BMW_init(
+ struct BMWalker *walker, BMesh *bm, int type,
+ short mask_vert, short mask_edge, short mask_face,
+ BMWFlag flag,
+ int layer);
void *BMW_begin(BMWalker *walker, void *start);
void *BMW_step(struct BMWalker *walker);
void BMW_end(struct BMWalker *walker);
@@ -92,6 +93,11 @@ void BMW_state_remove(BMWalker *walker);
void *BMW_walk(BMWalker *walker);
void BMW_reset(BMWalker *walker);
+#define BMW_ITER(ele, walker, data) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMW_begin(walker, (BM_CHECK_TYPE_ELEM(data), data)); \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMW_step(walker))
+
/*
* example of usage, walking over an island of tool flagged faces:
*
@@ -108,8 +114,10 @@ void BMW_reset(BMWalker *walker);
enum {
BMW_VERT_SHELL,
+ BMW_LOOP_SHELL,
+ BMW_LOOP_SHELL_WIRE,
BMW_FACE_SHELL,
- BMW_LOOP,
+ BMW_EDGELOOP,
BMW_FACELOOP,
BMW_EDGERING,
BMW_EDGEBOUNDARY,
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index b7bf80b0e3f..cd08604541b 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -223,6 +223,268 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
/** \} */
+/** \name LoopShell Walker
+ * \{
+ *
+ * Starts at any element on the mesh and walks over the 'shell' it belongs
+ * to via visiting connected loops.
+ *
+ * \note this is mainly useful to loop over a shell delimited by edges.
+ */
+static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
+{
+ BMwLoopShellWalker *shellWalk = NULL;
+
+ if (BLI_gset_haskey(walker->visit_set, l)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curloop = l;
+ BLI_gset_insert(walker->visit_set, l);
+}
+
+static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
+{
+ BMIter iter;
+ BMHeader *h = data;
+
+ if (UNLIKELY(h == NULL)) {
+ return;
+ }
+
+ switch (h->htype) {
+ case BM_LOOP:
+ {
+ /* starting the walk at a vert, add all the edges
+ * to the worklist */
+ BMLoop *l = (BMLoop *)h;
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ break;
+ }
+
+ case BM_VERT:
+ {
+ BMVert *v = (BMVert *)h;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ break;
+ }
+ case BM_EDGE:
+ {
+ BMEdge *e = (BMEdge *)h;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &iter, e, BM_LOOPS_OF_EDGE) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ BMFace *f = (BMFace *)h;
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ /* walker will handle other loops within the face */
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void *bmw_LoopShellWalker_yield(BMWalker *walker)
+{
+ BMwLoopShellWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curloop;
+}
+
+static void bmw_LoopShellWalker_step_impl(BMWalker *walker, BMLoop *l)
+{
+ BMEdge *e_edj_pair[2];
+ int i;
+
+ /* seems paranoid, but one caller also walks edges */
+ BLI_assert(l->head.htype == BM_LOOP);
+
+ bmw_LoopShellWalker_visitLoop(walker, l->next);
+ bmw_LoopShellWalker_visitLoop(walker, l->prev);
+
+ e_edj_pair[0] = l->e;
+ e_edj_pair[1] = l->prev->e;
+
+ for (i = 0; i < 2; i++) {
+ BMEdge *e = e_edj_pair[i];
+ if (bmw_mask_check_edge(walker, e)) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = e->l;
+ do {
+ BMLoop *l_radial = (l_iter->v == l->v) ? l_iter : l_iter->next;
+ BLI_assert(l_radial->v == l->v);
+ if (l != l_radial) {
+ bmw_LoopShellWalker_visitLoop(walker, l_radial);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ }
+}
+
+static void *bmw_LoopShellWalker_step(BMWalker *walker)
+{
+ BMwLoopShellWalker *swalk, owalk;
+ BMLoop *l;
+
+ BMW_state_remove_r(walker, &owalk);
+ swalk = &owalk;
+
+ l = swalk->curloop;
+ bmw_LoopShellWalker_step_impl(walker, l);
+
+ return l;
+}
+
+/** \} */
+
+/** \name LoopShell & 'Wire' Walker
+ * \{
+ *
+ * Piggyback ontop of #BMwLoopShellWalker, but also walk over wire edges
+ * This isn't elegant but users expect it when selecting linked,
+ * so we can support delimiters _and_ walking over wire edges.
+ *
+ * Details:
+ * - can yield edges (as well as loops)
+ * - only step over wire edges.
+ * - verts and edges are stored in `visit_set_alt`.
+ */
+
+static void bmw_LoopShellWalker_visitEdgeWire(BMWalker *walker, BMEdge *e)
+{
+ BMwLoopShellWireWalker *shellWalk = NULL;
+
+ BLI_assert(BM_edge_is_wire(e));
+
+ if (BLI_gset_haskey(walker->visit_set_alt, e)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curelem = (BMElem *)e;
+ BLI_gset_insert(walker->visit_set_alt, e);
+}
+
+static void bmw_LoopShellWireWalker_visitVert(BMWalker *walker, BMVert *v, const BMEdge *e_from)
+{
+ BMEdge *e;
+
+ BLI_assert(v->head.htype == BM_VERT);
+
+ if (BLI_gset_haskey(walker->visit_set_alt, v)) {
+ return;
+ }
+
+ e = v->e;
+ do {
+ if (BM_edge_is_wire(e) && (e != e_from)) {
+ BMVert *v_other;
+ BMIter iter;
+ BMLoop *l;
+
+ bmw_LoopShellWalker_visitEdgeWire(walker, e);
+
+ /* check if we step onto a non-wire vertex */
+ v_other = BM_edge_other_vert(e, v);
+ BM_ITER_ELEM (l, &iter, v_other, BM_LOOPS_OF_VERT) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
+
+ BLI_gset_insert(walker->visit_set_alt, v);
+}
+
+static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
+{
+ BMHeader *h = data;
+
+ if (UNLIKELY(h == NULL)) {
+ return;
+ }
+
+ bmw_LoopShellWalker_begin(walker, data);
+
+ switch (h->htype) {
+ case BM_LOOP:
+ {
+ BMLoop *l = (BMLoop *)h;
+ bmw_LoopShellWireWalker_visitVert(walker, l->v, NULL);
+ break;
+ }
+
+ case BM_VERT:
+ {
+ BMVert *v = (BMVert *)h;
+ if (v->e) {
+ bmw_LoopShellWireWalker_visitVert(walker, v, NULL);
+ }
+ break;
+ }
+ case BM_EDGE:
+ {
+ BMEdge *e = (BMEdge *)h;
+ if (BM_edge_is_wire(e)) {
+ bmw_LoopShellWalker_visitEdgeWire(walker, e);
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ /* wire verts will be walked over */
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void *bmw_LoopShellWireWalker_yield(BMWalker *walker)
+{
+ BMwLoopShellWireWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curelem;
+}
+
+static void *bmw_LoopShellWireWalker_step(BMWalker *walker)
+{
+ BMwLoopShellWireWalker *swalk, owalk;
+
+ BMW_state_remove_r(walker, &owalk);
+ swalk = &owalk;
+
+ if (swalk->curelem->head.htype == BM_LOOP) {
+ BMLoop *l = (BMLoop *)swalk->curelem;
+
+ bmw_LoopShellWalker_step_impl(walker, l);
+
+ bmw_LoopShellWireWalker_visitVert(walker, l->v, NULL);
+
+ return l;
+ }
+ else {
+ BMEdge *e = (BMEdge *)swalk->curelem;
+
+ BLI_assert(e->head.htype == BM_EDGE);
+
+ bmw_LoopShellWireWalker_visitVert(walker, e->v1, e);
+ bmw_LoopShellWireWalker_visitVert(walker, e->v2, e);
+
+ return e;
+ }
+}
+
+/** \} */
+
/** \name FaceShell Walker
* \{
@@ -543,9 +805,9 @@ static bool bm_edge_is_single(BMEdge *e)
(BM_edge_is_boundary(e->l->next->e) || BM_edge_is_boundary(e->l->prev->e)));
}
-static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
+static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
{
- BMwLoopWalker *lwalk = NULL, owalk, *owalk_pt;
+ BMwEdgeLoopWalker *lwalk = NULL, owalk, *owalk_pt;
BMEdge *e = data;
BMVert *v;
const int vert_edge_count[2] = {
@@ -593,7 +855,7 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
/* rewind */
while ((owalk_pt = BMW_current_state(walker))) {
- owalk = *((BMwLoopWalker *)owalk_pt);
+ owalk = *((BMwEdgeLoopWalker *)owalk_pt);
BMW_walk(walker);
}
@@ -606,16 +868,16 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
BLI_gset_insert(walker->visit_set, owalk.cur);
}
-static void *bmw_LoopWalker_yield(BMWalker *walker)
+static void *bmw_EdgeLoopWalker_yield(BMWalker *walker)
{
- BMwLoopWalker *lwalk = BMW_current_state(walker);
+ BMwEdgeLoopWalker *lwalk = BMW_current_state(walker);
return lwalk->cur;
}
-static void *bmw_LoopWalker_step(BMWalker *walker)
+static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
{
- BMwLoopWalker *lwalk, owalk;
+ BMwEdgeLoopWalker *lwalk, owalk;
BMEdge *e, *nexte = NULL;
BMLoop *l;
BMVert *v;
@@ -1179,17 +1441,16 @@ static void *bmw_UVEdgeWalker_yield(BMWalker *walker)
static void *bmw_UVEdgeWalker_step(BMWalker *walker)
{
const int type = walker->bm->ldata.layers[walker->layer].type;
+ const int offset = walker->bm->ldata.layers[walker->layer].offset;
+
BMwUVEdgeWalker *lwalk, owalk;
- BMLoop *l, *l2, *l3, *nl, *cl;
- BMIter liter;
- void *d1, *d2;
- int i, j, rlen;
+ BMLoop *l;
+ int i;
BMW_state_remove_r(walker, &owalk);
lwalk = &owalk;
l = lwalk->l;
- nl = l->next;
if (!bmw_mask_check_edge(walker, l->e)) {
return l;
@@ -1198,37 +1459,40 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker)
/* go over loops around l->v and nl->v and see which ones share l and nl's
* mloopuv's coordinates. in addition, push on l->next if necessary */
for (i = 0; i < 2; i++) {
- cl = i ? nl : l;
- BM_ITER_ELEM (l2, &liter, cl->v, BM_LOOPS_OF_VERT) {
- d1 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
- cl->head.data, walker->layer);
-
- rlen = BM_edge_face_count(l2->e);
- for (j = 0; j < rlen; j++) {
- if (BLI_gset_haskey(walker->visit_set, l2)) {
+ BMIter liter;
+ BMLoop *l_pivot, *l_radial;
+
+ l_pivot = i ? l->next : l;
+ BM_ITER_ELEM (l_radial, &liter, l_pivot->v, BM_LOOPS_OF_VERT) {
+ BMLoop *l_radial_first = l_radial;
+ void *data_pivot = BM_ELEM_CD_GET_VOID_P(l_pivot, offset);
+
+ do {
+ BMLoop *l_other;
+ void *data_other;
+
+ if (BLI_gset_haskey(walker->visit_set, l_radial)) {
continue;
}
- if (!bmw_mask_check_edge(walker, l2->e)) {
- if (l2->v != cl->v) {
+ if (l_radial->v != l_pivot->v) {
+ if (!bmw_mask_check_edge(walker, l_radial->e)) {
continue;
}
}
- l3 = l2->v != cl->v ? l2->next : l2;
- d2 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
- l3->head.data, walker->layer);
+ l_other = (l_radial->v != l_pivot->v) ? l_radial->next : l_radial;
+ data_other = BM_ELEM_CD_GET_VOID_P(l_other, offset);
- if (!CustomData_data_equals(type, d1, d2))
+ if (!CustomData_data_equals(type, data_pivot, data_other))
continue;
-
+
lwalk = BMW_state_add(walker);
- BLI_gset_insert(walker->visit_set, l2);
+ BLI_gset_insert(walker->visit_set, l_radial);
- lwalk->l = l2;
+ lwalk->l = l_radial;
- l2 = l2->radial_next;
- }
+ } while ((l_radial = l_radial->radial_next) != l_radial_first);
}
}
@@ -1248,6 +1512,26 @@ static BMWalker bmw_VertShellWalker_Type = {
BM_EDGE, /* valid restrict masks */
};
+static BMWalker bmw_LoopShellWalker_Type = {
+ BM_FACE | BM_LOOP | BM_EDGE | BM_VERT,
+ bmw_LoopShellWalker_begin,
+ bmw_LoopShellWalker_step,
+ bmw_LoopShellWalker_yield,
+ sizeof(BMwLoopShellWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
+static BMWalker bmw_LoopShellWireWalker_Type = {
+ BM_FACE | BM_LOOP | BM_EDGE | BM_VERT,
+ bmw_LoopShellWireWalker_begin,
+ bmw_LoopShellWireWalker_step,
+ bmw_LoopShellWireWalker_yield,
+ sizeof(BMwLoopShellWireWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
static BMWalker bmw_FaceShellWalker_Type = {
BM_EDGE,
bmw_FaceShellWalker_begin,
@@ -1278,12 +1562,12 @@ static BMWalker bmw_IslandWalker_Type = {
BM_EDGE | BM_FACE, /* valid restrict masks */
};
-static BMWalker bmw_LoopWalker_Type = {
+static BMWalker bmw_EdgeLoopWalker_Type = {
BM_EDGE,
- bmw_LoopWalker_begin,
- bmw_LoopWalker_step,
- bmw_LoopWalker_yield,
- sizeof(BMwLoopWalker),
+ bmw_EdgeLoopWalker_begin,
+ bmw_EdgeLoopWalker_step,
+ bmw_EdgeLoopWalker_yield,
+ sizeof(BMwEdgeLoopWalker),
BMW_DEPTH_FIRST,
0, /* valid restrict masks */ /* could add flags here but so far none are used */
};
@@ -1340,8 +1624,10 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
BMWalker *bm_walker_types[] = {
&bmw_VertShellWalker_Type, /* BMW_VERT_SHELL */
+ &bmw_LoopShellWalker_Type, /* BMW_LOOP_SHELL */
+ &bmw_LoopShellWireWalker_Type, /* BMW_LOOP_SHELL_WIRE */
&bmw_FaceShellWalker_Type, /* BMW_FACE_SHELL */
- &bmw_LoopWalker_Type, /* BMW_LOOP */
+ &bmw_EdgeLoopWalker_Type, /* BMW_EDGELOOP */
&bmw_FaceLoopWalker_Type, /* BMW_FACELOOP */
&bmw_EdgeringWalker_Type, /* BMW_EDGERING */
&bmw_EdgeboundaryWalker_Type, /* BMW_EDGEBOUNDARY */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_private.h b/source/blender/bmesh/intern/bmesh_walkers_private.h
index 82d1e760db7..66d812b45d0 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_private.h
+++ b/source/blender/bmesh/intern/bmesh_walkers_private.h
@@ -45,6 +45,16 @@ typedef struct BMwShellWalker {
BMEdge *curedge;
} BMwShellWalker;
+typedef struct BMwLoopShellWalker {
+ BMwGenericWalker header;
+ BMLoop *curloop;
+} BMwLoopShellWalker;
+
+typedef struct BMwLoopShellWireWalker {
+ BMwGenericWalker header;
+ BMElem *curelem;
+} BMwLoopShellWireWalker;
+
typedef struct BMwIslandboundWalker {
BMwGenericWalker header;
BMLoop *base;
@@ -57,14 +67,14 @@ typedef struct BMwIslandWalker {
BMFace *cur;
} BMwIslandWalker;
-typedef struct BMwLoopWalker {
+typedef struct BMwEdgeLoopWalker {
BMwGenericWalker header;
BMEdge *cur, *start;
BMVert *lastv, *startv;
BMFace *f_hub;
bool is_boundary; /* boundary looping changes behavior */
bool is_single; /* single means the edge verts are only connected to 1 face */
-} BMwLoopWalker;
+} BMwEdgeLoopWalker;
typedef struct BMwFaceLoopWalker {
BMwGenericWalker header;
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 6002dcf2c0d..b4570e03c83 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -87,8 +87,9 @@ static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BM
}
/* el_b can have any offset */
-static float bm_edgeloop_offset_length(LinkData *el_a, LinkData *el_b,
- LinkData *el_b_first, const float len_max)
+static float bm_edgeloop_offset_length(
+ LinkData *el_a, LinkData *el_b,
+ LinkData *el_b_first, const float len_max)
{
float len = 0.0f;
BLI_assert(el_a->prev == NULL); /* must be first */
@@ -137,10 +138,11 @@ static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK);
}
-static void bridge_loop_pair(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- const bool use_merge, const float merge_factor, const int twist_offset)
+static void bridge_loop_pair(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ const bool use_merge, const float merge_factor, const int twist_offset)
{
const float eps = 0.00001f;
LinkData *el_a_first, *el_b_first;
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
index a00f65bd10f..107aead6994 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -79,8 +79,8 @@ static bool bm_face_split_by_concave(
struct Heap *pf_heap, struct EdgeHash *pf_ehash)
{
const int f_base_len = f_base->len;
- int faces_array_tot = f_base->len - 3;
- int edges_array_tot = f_base->len - 3;
+ int faces_array_tot = f_base_len - 3;
+ int edges_array_tot = f_base_len - 3;
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
const int quad_method = 0, ngon_method = 0; /* beauty */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index fbc128b375f..cf0e233fe6c 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -152,8 +152,9 @@ static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3])
/** \} */
-static int state_isect_co_pair(const PathContext *pc,
- const float co_a[3], const float co_b[3])
+static int state_isect_co_pair(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3])
{
const float diff_a = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_a) - pc->axis_sep;
const float diff_b = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_b) - pc->axis_sep;
@@ -169,15 +170,17 @@ static int state_isect_co_pair(const PathContext *pc,
}
}
-static int state_isect_co_exact(const PathContext *pc,
- const float co[3])
+static int state_isect_co_exact(
+ const PathContext *pc,
+ const float co[3])
{
const float diff = dot_m3_v3_row_x((float (*)[3])pc->matrix, co) - pc->axis_sep;
return (fabsf(diff) <= CONNECT_EPS);
}
-static float state_calc_co_pair_fac(const PathContext *pc,
- const float co_a[3], const float co_b[3])
+static float state_calc_co_pair_fac(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3])
{
float diff_a, diff_b, diff_tot;
@@ -187,9 +190,10 @@ static float state_calc_co_pair_fac(const PathContext *pc,
return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f;
}
-static void state_calc_co_pair(const PathContext *pc,
- const float co_a[3], const float co_b[3],
- float r_co[3])
+static void state_calc_co_pair(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3],
+ float r_co[3])
{
const float fac = state_calc_co_pair_fac(pc, co_a, co_b);
interp_v3_v3v3(r_co, co_a, co_b, fac);
@@ -213,8 +217,9 @@ static bool state_link_find(const PathLinkState *state, BMElem *ele)
return false;
}
-static void state_link_add(PathContext *pc, PathLinkState *state,
- BMElem *ele, BMElem *ele_from)
+static void state_link_add(
+ PathContext *pc, PathLinkState *state,
+ BMElem *ele, BMElem *ele_from)
{
PathLink *step_new = BLI_mempool_alloc(pc->link_pool);
BLI_assert(ele != ele_from);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index ecb41363761..ac0466a74d2 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -494,7 +494,7 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
{
- BMO_op_callf(bm, flag, "collapse edges=%fe", oflag);
+ BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true);
}
void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index a5a6480c187..33048e6c86e 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -44,9 +44,10 @@
*
* Copy an existing vertex from one bmesh to another.
*/
-static BMVert *bmo_vert_copy(BMOperator *op,
- BMOpSlot *slot_vertmap_out,
- BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
+static BMVert *bmo_vert_copy(
+ BMOperator *op,
+ BMOpSlot *slot_vertmap_out,
+ BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
{
BMVert *v_dst;
@@ -72,12 +73,13 @@ static BMVert *bmo_vert_copy(BMOperator *op,
*
* Copy an existing edge from one bmesh to another.
*/
-static BMEdge *bmo_edge_copy(BMOperator *op,
- BMOpSlot *slot_edgemap_out,
- BMOpSlot *slot_boundarymap_out,
- BMesh *bm_dst, BMesh *bm_src,
- BMEdge *e_src,
- GHash *vhash, GHash *ehash)
+static BMEdge *bmo_edge_copy(
+ BMOperator *op,
+ BMOpSlot *slot_edgemap_out,
+ BMOpSlot *slot_boundarymap_out,
+ BMesh *bm_dst, BMesh *bm_src,
+ BMEdge *e_src,
+ GHash *vhash, GHash *ehash)
{
BMEdge *e_dst;
BMVert *e_dst_v1, *e_dst_v2;
@@ -131,11 +133,12 @@ static BMEdge *bmo_edge_copy(BMOperator *op,
*
* Copy an existing face from one bmesh to another.
*/
-static BMFace *bmo_face_copy(BMOperator *op,
- BMOpSlot *slot_facemap_out,
- BMesh *bm_dst, BMesh *bm_src,
- BMFace *f_src,
- GHash *vhash, GHash *ehash)
+static BMFace *bmo_face_copy(
+ BMOperator *op,
+ BMOpSlot *slot_facemap_out,
+ BMesh *bm_dst, BMesh *bm_src,
+ BMFace *f_src,
+ GHash *vhash, GHash *ehash)
{
BMFace *f_dst;
BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index aa92c3054cd..435b9e60949 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -39,6 +39,8 @@
#include "intern/bmesh_operators_private.h" /* own include */
+#define USE_EDGE_REGION_FLAGS
+
enum {
EXT_INPUT = 1,
EXT_KEEP = 2,
@@ -287,6 +289,39 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP);
}
+#ifdef USE_EDGE_REGION_FLAGS
+/**
+ * When create an edge for an extruded face region
+ * check surrounding edge flags before creating a new edge.
+ */
+static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
+{
+ BMEdge *e_iter;
+ const char hflag_enable = BM_ELEM_SEAM;
+ const char hflag_disable = BM_ELEM_SMOOTH;
+ bool ok = false;
+
+ r_e_hflag[0] = 0x0;
+ r_e_hflag[1] = 0xff;
+
+ /* clear flags on both disks */
+ e_iter = v->e;
+ do {
+ if (e_iter->l && !BM_edge_is_boundary(e_iter)) {
+ r_e_hflag[0] |= e_iter->head.hflag;
+ r_e_hflag[1] &= e_iter->head.hflag;
+ ok = true;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e);
+
+ if (ok) {
+ r_e_hflag[0] &= hflag_enable;
+ r_e_hflag[1] = hflag_disable & ~r_e_hflag[1];
+ }
+ return ok;
+}
+#endif /* USE_EDGE_REGION_FLAGS */
+
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
{
BMOperator dupeop, delop;
@@ -413,6 +448,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
BMVert *f_verts[4];
+#ifdef USE_EDGE_REGION_FLAGS
+ BMEdge *f_edges[4];
+#endif
/* this should always be wire, so this is mainly a speedup to avoid map lookup */
if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) {
@@ -465,8 +503,38 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f_verts[3] = e_new->v2;
}
- /* not sure what to do about example face, pass NULL for now */
+#ifdef USE_EDGE_REGION_FLAGS
+ /* handle new edges */
+ f_edges[0] = e;
+ f_edges[2] = e_new;
+
+ f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]);
+ if (f_edges[1] == NULL) {
+ char e_hflag[2];
+ bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag);
+ f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP);
+ if (e_hflag_ok) {
+ BM_elem_flag_enable(f_edges[1], e_hflag[0]);
+ BM_elem_flag_disable(f_edges[1], e_hflag[1]);
+ }
+ }
+
+ f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]);
+ if (f_edges[3] == NULL) {
+ char e_hflag[2];
+ bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag);
+ f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP);
+ if (e_hflag_ok) {
+ BM_elem_flag_enable(f_edges[3], e_hflag[0]);
+ BM_elem_flag_disable(f_edges[3], e_hflag[1]);
+ }
+ }
+
+ f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP);
+#else
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
+#endif
+
bm_extrude_copy_face_loop_attributes(bm, f);
}
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index d9f50ac891c..85bca744d86 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -61,8 +61,9 @@ static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data))
/**
* Copy all attributes from adjacent untagged faces.
*/
-static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l,
- const bool use_normals, const bool use_data)
+static void bm_face_copy_shared_all(
+ BMesh *bm, BMLoop *l,
+ const bool use_normals, const bool use_data)
{
BMLoop *l_other = l->radial_next;
BMFace *f = l->f, *f_other;
@@ -90,8 +91,9 @@ static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l,
/**
* Flood fill attributes.
*/
-static unsigned int bmesh_face_attribute_fill(BMesh *bm,
- const bool use_normals, const bool use_data)
+static unsigned int bmesh_face_attribute_fill(
+ BMesh *bm,
+ const bool use_normals, const bool use_data)
{
BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *);
BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index dd954adcd55..fd1e91a0b30 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -114,8 +114,9 @@ static void quad_verts_to_barycentric_tri(
/**
* Assign a loop pair from 2 verts (which _must_ share an edge)
*/
-static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b,
- BMLoop *l_pair[2])
+static void bm_loop_pair_from_verts(
+ BMVert *v_a, BMVert *v_b,
+ BMLoop *l_pair[2])
{
BMEdge *e = BM_edge_exists(v_a, v_b);
if (e->l) {
@@ -185,8 +186,9 @@ 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,
- float (*weight_table)[4])
+static void barycentric_weights_v2_grid_cache(
+ const unsigned int xtot, const unsigned int ytot,
+ float (*weight_table)[4])
{
float x_step = 1.0f / (float)(xtot - 1);
float y_step = 1.0f / (float)(ytot - 1);
@@ -216,9 +218,10 @@ static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const uns
*
* \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,
- const short mat_nr, const bool use_smooth,
- const bool use_flip, const bool use_interp_simple)
+static void bm_grid_fill_array(
+ BMesh *bm, BMVert **v_grid, const unsigned int 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);
@@ -485,10 +488,11 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt
#undef XY
}
-static void bm_grid_fill(BMesh *bm,
- struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b,
- struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b,
- const short mat_nr, const bool use_smooth, const bool use_interp_simple)
+static void bm_grid_fill(
+ BMesh *bm,
+ struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b,
+ struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b,
+ const short mat_nr, const bool use_smooth, const bool use_interp_simple)
{
#define USE_FLIP_DETECT
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index fb99c9777d0..2dfad5a1f47 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -67,8 +67,9 @@ typedef struct HullTriangle {
/*************************** Hull Triangles ***************************/
-static void hull_add_triangle(BMesh *bm, GSet *hull_triangles, BLI_mempool *pool,
- BMVert *v1, BMVert *v2, BMVert *v3)
+static void hull_add_triangle(
+ BMesh *bm, GSet *hull_triangles, BLI_mempool *pool,
+ BMVert *v1, BMVert *v2, BMVert *v3)
{
HullTriangle *t;
int i;
@@ -189,8 +190,9 @@ static LinkData *final_edges_find_link(ListBase *adj, BMVert *v)
return NULL;
}
-static int hull_final_edges_lookup(HullFinalEdges *final_edges,
- BMVert *v1, BMVert *v2)
+static int hull_final_edges_lookup(
+ HullFinalEdges *final_edges,
+ BMVert *v1, BMVert *v2)
{
ListBase *adj;
@@ -259,8 +261,9 @@ static void hull_final_edges_free(HullFinalEdges *final_edges)
/**************************** Final Output ****************************/
-static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles,
- HullFinalEdges *final_edges)
+static void hull_remove_overlapping(
+ BMesh *bm, GSet *hull_triangles,
+ HullFinalEdges *final_edges)
{
GSetIterator hull_iter;
@@ -296,8 +299,9 @@ static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles,
}
}
-static void hull_mark_interior_elements(BMesh *bm, BMOperator *op,
- HullFinalEdges *final_edges)
+static void hull_mark_interior_elements(
+ BMesh *bm, BMOperator *op,
+ HullFinalEdges *final_edges)
{
BMEdge *e;
BMFace *f;
@@ -425,8 +429,9 @@ static int hull_input_vert_count(BMOperator *op)
return count;
}
-static BMVert **hull_input_verts_copy(BMOperator *op,
- const int num_input_verts)
+static BMVert **hull_input_verts_copy(
+ BMOperator *op,
+ const int num_input_verts)
{
BMOIter oiter;
BMVert *v;
@@ -441,8 +446,9 @@ static BMVert **hull_input_verts_copy(BMOperator *op,
return input_verts;
}
-static float (*hull_verts_for_bullet(BMVert **input_verts,
- const int num_input_verts))[3]
+static float (*hull_verts_for_bullet(
+ BMVert **input_verts,
+ const int num_input_verts))[3]
{
float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__);
int i;
@@ -454,9 +460,10 @@ static float (*hull_verts_for_bullet(BMVert **input_verts,
return coords;
}
-static BMVert **hull_verts_from_bullet(plConvexHull hull,
- BMVert **input_verts,
- const int num_input_verts)
+static BMVert **hull_verts_from_bullet(
+ plConvexHull hull,
+ BMVert **input_verts,
+ const int num_input_verts)
{
const int num_verts = plConvexHullNumVertices(hull);
BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) *
@@ -478,9 +485,10 @@ static BMVert **hull_verts_from_bullet(plConvexHull hull,
return hull_verts;
}
-static void hull_from_bullet(BMesh *bm, BMOperator *op,
- GSet *hull_triangles,
- BLI_mempool *pool)
+static void hull_from_bullet(
+ BMesh *bm, BMOperator *op,
+ GSet *hull_triangles,
+ BLI_mempool *pool)
{
int *fvi = NULL;
BLI_array_declare(fvi);
@@ -529,6 +537,9 @@ static void hull_from_bullet(BMesh *bm, BMOperator *op,
}
BLI_array_free(fvi);
+
+ plConvexHullDelete(hull);
+
MEM_freeN(hull_verts);
MEM_freeN(coords);
MEM_freeN(input_verts);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index 27e140eb990..6664bf6dc46 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -660,9 +660,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
es->l = es->e_old->l; /* must be a boundary */
}
-
/* run the separate arg */
- bmesh_edge_separate(bm, es->e_old, es->l, false);
+ if (!BM_edge_is_boundary(es->e_old)) {
+ bmesh_edge_separate(bm, es->e_old, es->l, false);
+ }
/* calc edge-split info */
es->e_new = es->l->e;
@@ -974,7 +975,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
v_glue = v_split;
}
else {
- BM_vert_splice(bm, v_split, v_glue);
+ BM_vert_splice(bm, v_glue, v_split);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 6562f26062f..b873e6bacb3 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -42,173 +42,276 @@
#include "intern/bmesh_operators_private.h" /* own include */
-#define FACE_OUT (1 << 0)
-
/* assumes edges are validated before reaching this poin */
-static float measure_facepair(const float v1[3], const float v2[3],
- const float v3[3], const float v4[3], float limit)
+static float quad_calc_error(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3])
{
/* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make */
/* Note: this is more complicated than it needs to be and should be cleaned up.. */
- float n1[3], n2[3], measure = 0.0f, angle1, angle2, diff;
- float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3];
- float minarea, maxarea, areaA, areaB;
-
- /* First Test: Normal difference */
- normal_tri_v3(n1, v1, v2, v3);
- normal_tri_v3(n2, v1, v3, v4);
- angle1 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
-
- normal_tri_v3(n1, v2, v3, v4);
- normal_tri_v3(n2, v4, v1, v2);
- angle2 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
-
- measure += (angle1 + angle2) * 0.5f;
- if (measure > limit) {
- return measure;
+ float error = 0.0f;
+
+ /* Normal difference */
+ {
+ float n1[3], n2[3];
+ float angle_a, angle_b;
+ float diff;
+
+ normal_tri_v3(n1, v1, v2, v3);
+ normal_tri_v3(n2, v1, v3, v4);
+ angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
+
+ normal_tri_v3(n1, v2, v3, v4);
+ normal_tri_v3(n2, v4, v1, v2);
+ angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
+
+ diff = (angle_a + angle_b) / (float)(M_PI * 2);
+
+ error += diff;
}
- /* Second test: Colinearity */
- sub_v3_v3v3(edgeVec1, v1, v2);
- sub_v3_v3v3(edgeVec2, v2, v3);
- sub_v3_v3v3(edgeVec3, v3, v4);
- sub_v3_v3v3(edgeVec4, v4, v1);
-
- normalize_v3(edgeVec1);
- normalize_v3(edgeVec2);
- normalize_v3(edgeVec3);
- normalize_v3(edgeVec4);
-
- /* a completely skinny face is 'pi' after halving */
- diff = 0.25f * (fabsf(angle_normalized_v3v3(edgeVec1, edgeVec2) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec2, edgeVec3) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec3, edgeVec4) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec4, edgeVec1) - (float)M_PI_2));
-
- if (!diff) {
- return 0.0;
+ /* Colinearity */
+ {
+ float edge_vecs[4][3];
+ float diff;
+
+ sub_v3_v3v3(edge_vecs[0], v1, v2);
+ sub_v3_v3v3(edge_vecs[1], v2, v3);
+ sub_v3_v3v3(edge_vecs[2], v3, v4);
+ sub_v3_v3v3(edge_vecs[3], v4, v1);
+
+ normalize_v3(edge_vecs[0]);
+ normalize_v3(edge_vecs[1]);
+ normalize_v3(edge_vecs[2]);
+ normalize_v3(edge_vecs[3]);
+
+ /* a completely skinny face is 'pi' after halving */
+ diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) / (float)(M_PI * 2);
+
+ error += diff;
}
- measure += diff;
- if (measure > limit) {
- return measure;
+ /* Concavity */
+ {
+ float area_min, area_max, area_a, area_b;
+ float diff;
+
+ area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4);
+ area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2);
+
+ area_min = min_ff(area_a, area_b);
+ area_max = max_ff(area_a, area_b);
+
+ diff = area_max ? (1.0 - (area_min / area_max)) : 1.0f;
+
+ error += diff;
}
- /* Third test: Concavity */
- areaA = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4);
- areaB = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2);
+ return error;
+}
+
+static void bm_edge_to_quad_verts(const BMEdge *e, const BMVert *r_v_quad[4])
+{
+ BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
+ BLI_assert(BM_edge_is_manifold(e));
+ r_v_quad[0] = e->l->v;
+ r_v_quad[1] = e->l->prev->v;
+ r_v_quad[2] = e->l->next->v;
+ r_v_quad[3] = e->l->radial_next->prev->v;
+}
+
+/* cache customdata delimiters */
+struct DelimitData_CD {
+ int cd_type;
+ int cd_size;
+ int cd_offset;
+ int cd_offset_end;
+};
+
+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;
- if (areaA <= areaB) minarea = areaA;
- else minarea = areaB;
+ float angle_face;
+ float angle_face__cos;
- if (areaA >= areaB) maxarea = areaA;
- else maxarea = areaB;
+ float angle_shape;
- if (!maxarea) measure += 1;
- else measure += (1 - (minarea / maxarea));
+ struct DelimitData_CD cdata[4];
+ int cdata_len;
+};
- return measure;
+static bool bm_edge_is_contiguous_loop_cd_all(
+ const BMEdge *e, const struct DelimitData_CD *delimit_data)
+{
+ int cd_offset;
+ for (cd_offset = delimit_data->cd_offset;
+ cd_offset < delimit_data->cd_offset_end;
+ cd_offset += delimit_data->cd_size)
+ {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) {
+ return false;
+ }
+ }
+
+ return true;
}
-#define T2QUV_LIMIT 0.005f
-#define T2QCOL_LIMIT 3
+static bool bm_edge_delimit_cdata(
+ CustomData *ldata, CustomDataType type,
+ struct DelimitData_CD *r_delim_cd)
+{
+ const int layer_len = CustomData_number_of_layers(ldata, type);
+ r_delim_cd->cd_type = type;
+ r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type);
+ r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0);
+ r_delim_cd->cd_offset_end = r_delim_cd->cd_size * layer_len;
+ return (r_delim_cd->cd_offset != -1);
+}
-static bool bm_edge_faces_cmp(BMesh *bm, BMEdge *e, const bool do_uv, const bool do_tf, const bool do_vcol)
+static float bm_edge_is_delimit(
+ const BMEdge *e,
+ const struct DelimitData *delimit_data)
{
- /* first get loops */
- BMLoop *l[4];
-
- l[0] = e->l;
- l[2] = e->l->radial_next;
-
- /* match up loops on each side of an edge corresponding to each vert */
- if (l[0]->v == l[2]->v) {
- l[1] = l[0]->next;
- l[3] = l[1]->next;
+ BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f;
+#if 0
+ const bool is_contig = BM_edge_is_contiguous(e);
+ float angle;
+#endif
+
+ if ((delimit_data->do_seam) &&
+ (BM_elem_flag_test(e, BM_ELEM_SEAM)))
+ {
+ goto fail;
}
- else {
- l[1] = l[0]->next;
- l[3] = l[2];
- l[2] = l[3]->next;
+ if ((delimit_data->do_sharp) &&
+ (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0))
+ {
+ goto fail;
}
- /* Test UV's */
- if (do_uv) {
- const MLoopUV *luv[4] = {
- CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPUV),
- };
-
- /* do UV */
- if (luv[0] && (!compare_v2v2(luv[0]->uv, luv[2]->uv, T2QUV_LIMIT) ||
- !compare_v2v2(luv[1]->uv, luv[3]->uv, T2QUV_LIMIT)))
- {
- return false;
+ if ((delimit_data->do_mat) &&
+ (f_a->mat_nr != f_b->mat_nr))
+ {
+ goto fail;
+ }
+
+ if (delimit_data->do_angle_face) {
+ if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) {
+ goto fail;
}
}
- if (do_tf) {
- const MTexPoly *tp[2] = {
- CustomData_bmesh_get(&bm->pdata, l[0]->f->head.data, CD_MTEXPOLY),
- CustomData_bmesh_get(&bm->pdata, l[1]->f->head.data, CD_MTEXPOLY),
- };
+ if (delimit_data->do_angle_shape) {
+ const BMVert *verts[4];
+ bm_edge_to_quad_verts(e, verts);
- if (tp[0] && (tp[0]->tpage != tp[1]->tpage)) {
- return false;
+ /* if we're checking the shape at all, a flipped face is out of the question */
+ if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) {
+ goto fail;
+ }
+ else {
+ float edge_vecs[4][3];
+
+ sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co);
+ sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co);
+ sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co);
+ sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co);
+
+ normalize_v3(edge_vecs[0]);
+ normalize_v3(edge_vecs[1]);
+ normalize_v3(edge_vecs[2]);
+ normalize_v3(edge_vecs[3]);
+
+ if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) > delimit_data->angle_shape))
+ {
+ goto fail;
+ }
}
}
- /* Test Vertex Colors */
- if (do_vcol) {
- const MLoopCol *lcol[4] = {
- CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPCOL),
- };
-
- if (lcol[0]) {
- if (!compare_rgb_uchar((unsigned char *)&lcol[0]->r, (unsigned char *)&lcol[2]->r, T2QCOL_LIMIT) ||
- !compare_rgb_uchar((unsigned char *)&lcol[1]->r, (unsigned char *)&lcol[3]->r, T2QCOL_LIMIT))
- {
- return false;
+ if (delimit_data->cdata_len) {
+ int i;
+ for (i = 0; i < delimit_data->cdata_len; i++) {
+ if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) {
+ goto fail;
}
}
}
+ return false;
+
+fail:
return true;
}
-#define EDGE_MARK 1
-#define EDGE_CHOSEN 2
-
-#define FACE_MARK 1
-#define FACE_INPUT 2
-
+#define EDGE_MARK (1 << 0)
+#define FACE_OUT (1 << 0)
+#define FACE_INPUT (1 << 2)
void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
{
- const bool do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp");
- const bool do_uv = BMO_slot_bool_get(op->slots_in, "cmp_uvs");
- const bool do_tf = do_uv; /* texture face, make make its own option eventually */
- const bool do_vcol = BMO_slot_bool_get(op->slots_in, "cmp_vcols");
- const bool do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials");
- const float limit = BMO_slot_float_get(op->slots_in, "limit");
+ float angle_face, angle_shape;
BMIter iter;
BMOIter siter;
BMFace *f;
- BMEdge *e, *e_next;
+ BMEdge *e;
/* data: edge-to-join, sort_value: error weight */
struct SortPointerByFloat *jedges;
unsigned i, totedge;
unsigned int totedge_tag = 0;
+ struct DelimitData delimit_data = {0};
+
+ delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam");
+ delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp");
+ delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials");
+
+ angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold");
+ if (angle_face < DEG2RADF(180.0f)) {
+ delimit_data.angle_face = angle_face;
+ delimit_data.angle_face__cos = cosf(angle_face);
+ delimit_data.do_angle_face = true;
+ }
+ else {
+ delimit_data.do_angle_face = false;
+ }
+
+ angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold");
+ if (angle_shape < DEG2RADF(180.0f)) {
+ delimit_data.angle_shape = angle_shape;
+ delimit_data.do_angle_shape = true;
+ }
+ else {
+ delimit_data.do_angle_shape = false;
+ }
+
+ if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") &&
+ bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len]))
+ {
+ delimit_data.cdata_len += 1;
+ }
+
+ delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1;
+ if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") &&
+ bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len]))
+ {
+ delimit_data.cdata_len += 1;
+ }
+
/* flag all edges of all input face */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
@@ -220,10 +323,13 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMFace *f_a, *f_b;
if (BM_edge_face_pair(e, &f_a, &f_b) &&
- (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
+ (BMO_elem_flag_test(bm, f_a, FACE_INPUT) &&
+ BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
{
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
- totedge_tag++;
+ if (!bm_edge_is_delimit(e, &delimit_data)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ totedge_tag++;
+ }
}
}
@@ -236,36 +342,19 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
i = 0;
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMVert *v1, *v2, *v3, *v4;
- BMFace *f_a, *f_b;
- float measure;
+ const BMVert *verts[4];
+ float error;
if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
continue;
- f_a = e->l->f;
- f_b = e->l->radial_next->f;
+ bm_edge_to_quad_verts(e, verts);
- if (do_sharp && !BM_elem_flag_test(e, BM_ELEM_SMOOTH))
- continue;
+ error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co);
- if (do_mat && f_a->mat_nr != f_b->mat_nr)
- continue;
-
- if ((do_uv || do_tf || do_vcol) && (bm_edge_faces_cmp(bm, e, do_uv, do_tf, do_vcol) == false))
- continue;
-
- v1 = e->l->v;
- v2 = e->l->prev->v;
- v3 = e->l->next->v;
- v4 = e->l->radial_next->prev->v;
-
- measure = measure_facepair(v1->co, v2->co, v3->co, v4->co, limit);
- if (measure < limit) {
- jedges[i].data = e;
- jedges[i].sort_value = measure;
- i++;
- }
+ jedges[i].data = e;
+ jedges[i].sort_value = error;
+ i++;
}
totedge = i;
@@ -279,27 +368,8 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
f_b = e->l->radial_next->f;
/* check if another edge already claimed this face */
- if ((BMO_elem_flag_test(bm, f_a, FACE_MARK) == false) ||
- (BMO_elem_flag_test(bm, f_b, FACE_MARK) == false))
- {
- BMO_elem_flag_enable(bm, f_a, FACE_MARK);
- BMO_elem_flag_enable(bm, f_b, FACE_MARK);
- BMO_elem_flag_enable(bm, e, EDGE_CHOSEN);
- }
- }
-
- MEM_freeN(jedges);
-
- /* join best weighted */
- BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- BMFace *f_new;
- BMFace *f_a, *f_b;
-
- if (!BMO_elem_flag_test(bm, e, EDGE_CHOSEN))
- continue;
-
- BM_edge_face_pair(e, &f_a, &f_b); /* checked above */
- if ((f_a->len == 3 && f_b->len == 3)) {
+ if ((f_a->len == 3) && (f_b->len == 3)) {
+ BMFace *f_new;
f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
if (f_new) {
BMO_elem_flag_enable(bm, f_new, FACE_OUT);
@@ -307,39 +377,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
}
}
- /* join 2-tri islands */
- BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
- BMLoop *l_a, *l_b;
- BMFace *f_a, *f_b;
-
- /* ok, this edge wasn't merged, check if it's
- * in a 2-tri-pair island, and if so merge */
- l_a = e->l;
- l_b = e->l->radial_next;
-
- f_a = l_a->f;
- f_b = l_b->f;
-
- /* check the other 2 edges in both tris are untagged */
- if ((f_a->len == 3 && f_b->len == 3) &&
- (BMO_elem_flag_test(bm, l_a->next->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_a->prev->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_b->next->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_b->prev->e, EDGE_MARK) == false) &&
- /* check for faces that use same verts, this is supported but raises an error
- * and cancels the operation when performed from editmode, since this is only
- * two triangles we only need to compare a single vertex */
- (LIKELY(l_a->prev->v != l_b->prev->v)))
- {
- BMFace *f_new;
- f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
- if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
- }
- }
- }
- }
+ MEM_freeN(jedges);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
new file mode 100644
index 00000000000..a2f3f0bb519
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -0,0 +1,290 @@
+/*
+ * ***** 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): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/operators/bmo_offset_edgeloops.c
+ * \ingroup bmesh
+ *
+ * Simple edge offset functionality.
+ *
+ * \note Actual offset is done by edge-slide.
+ * (this only changes topology)
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_alloca.h"
+#include "BLI_stackdefines.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+#define USE_CAP_OPTION
+
+#define ELE_NEW (1 << 0)
+
+#ifdef USE_CAP_OPTION
+#define ELE_VERT_ENDPOINT (1 << 1)
+#endif
+
+/* set for debugging */
+#define OFFSET 0.0f
+
+static BMFace *bm_face_split_walk_back(
+ BMesh *bm, BMLoop *l_src,
+ BMLoop **r_l)
+{
+ float (*cos)[3];
+ BMLoop *l_dst;
+ BMFace *f;
+ int num, i;
+
+ for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, num++) {
+ /* pass */
+ }
+
+ BLI_assert(num != 0);
+
+ cos = BLI_array_alloca(
+ cos, num);
+
+ for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, i++) {
+ copy_v3_v3(cos[num - (i + 1)], l_dst->v->co);
+ }
+
+ f = BM_face_split_n( bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL);
+
+ return f;
+}
+
+void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
+{
+ const int edges_num = BMO_slot_buffer_count(op->slots_in, "edges");
+ BMVert **verts;
+ STACK_DECLARE(verts);
+ int i;
+
+#ifdef USE_CAP_OPTION
+ bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint");
+ int v_edges_max = 0;
+#endif
+
+ BMOIter oiter;
+
+ /* only so we can detect new verts (index == -1) */
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ /* over alloc */
+ verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__);
+
+ STACK_INIT(verts, (edges_num * 2));
+
+ {
+ BMEdge *e;
+ BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) {
+ int j;
+
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+
+ for (j = 0; j < 2; j++) {
+ BMVert *v_edge = *(&(e->v1) + j);
+ if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v_edge, BM_ELEM_TAG);
+ STACK_PUSH(verts, v_edge);
+ }
+ }
+ }
+ }
+
+
+ /* -------------------------------------------------------------------- */
+ /* Remove verts only used by tagged edges */
+
+ for (i = 0; i < STACK_SIZE(verts); i++) {
+ BMIter iter;
+ int flag = 0;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
+ flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2;
+ if (flag == (1 | 2)) {
+ break;
+ }
+ }
+
+ /* only boundary verts are interesting */
+ if (flag != (1 | 2)) {
+ STACK_REMOVE(verts, i);
+ }
+ }
+
+ /* possible but unlikely we have no mixed vertices */
+ if (UNLIKELY(STACK_SIZE(verts) == 0)) {
+ MEM_freeN(verts);
+ return;
+ }
+
+ /* main loop */
+ for (i = 0; i < STACK_SIZE(verts); i++) {
+ int v_edges_num = 0;
+ int v_edges_num_untag = 0;
+ BMVert *v = verts[i];
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMVert *v_other;
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
+ BM_elem_flag_enable(l->f, BM_ELEM_TAG);
+ }
+
+ v_other = BM_edge_other_vert(e, v);
+ BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET);
+ }
+ else {
+ v_edges_num_untag += 1;
+ }
+
+ v_edges_num += 1;
+ }
+
+#ifdef USE_CAP_OPTION
+ if (v_edges_num_untag == 1) {
+ BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT);
+ }
+
+ CLAMP_MIN(v_edges_max, v_edges_num);
+#endif
+
+ }
+
+
+ for (i = 0; i < STACK_SIZE(verts); i++) {
+ BMVert *v = verts[i];
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(l->f, BM_ELEM_TAG) &&
+ (l->f->len != 3))
+ {
+ BMFace *f_cmp = l->f;
+ if ((BM_elem_index_get(l->next->v) == -1) &&
+ (BM_elem_index_get(l->prev->v) == -1))
+ {
+#ifdef USE_CAP_OPTION
+ if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0))
+#endif
+ {
+ BMLoop *l_new;
+ BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
+ BLI_assert(f_cmp == l->f);
+ BLI_assert(f_cmp != l_new->f);
+ UNUSED_VARS_NDEBUG(f_cmp);
+ BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ }
+ }
+ else if (l->f->len > 4) {
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG) !=
+ BM_elem_flag_test(l->prev->e, BM_ELEM_TAG))
+ {
+ if (BM_elem_index_get(l->next->v) == -1) {
+ if (BM_elem_index_get(l->prev->prev->v) == -1) {
+ BMLoop *l_new;
+ BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true);
+ BLI_assert(f_cmp == l->f);
+ BLI_assert(f_cmp != l_new->f);
+ BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ BM_elem_flag_disable(l->f, BM_ELEM_TAG);
+ }
+ else {
+ /* walk backwards */
+ BMLoop *l_new;
+ bm_face_split_walk_back(bm, l, &l_new);
+ do {
+ BMO_elem_flag_enable(bm, l_new->e, ELE_NEW);
+ l_new = l_new->next;
+ } while (BM_vert_is_edge_pair(l_new->v));
+ BM_elem_flag_disable(l->f, BM_ELEM_TAG);
+ }
+ }
+
+ /* Note: instead of duplicate code in alternate direction,
+ * we can be sure to hit the other vertex, so the code above runs. */
+#if 0
+ else if (BM_elem_index_get(l->prev->v) == -1) {
+ if (BM_elem_index_get(l->next->next->v) == -1) {
+ }
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+
+#ifdef USE_CAP_OPTION
+ if (use_cap_endpoint == false) {
+ BMVert **varr = BLI_array_alloca(varr, v_edges_max);
+ STACK_DECLARE(varr);
+ BMVert *v;
+
+ for (i = 0; i < STACK_SIZE(verts); i++) {
+ BMIter iter;
+ BMEdge *e;
+
+ v = verts[i];
+
+ STACK_INIT(varr, v_edges_max);
+
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other;
+ 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 */
+ v_other->e = e;
+ STACK_PUSH(varr, v_other);
+ }
+ }
+ }
+
+ while ((v = STACK_POP(varr))) {
+ bmesh_jekv(bm, v->e, v, true, false);
+ }
+ }
+ }
+#endif
+
+ MEM_freeN(verts);
+
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW);
+}
diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c
new file mode 100644
index 00000000000..4e3ac58a813
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_planar_faces.c
@@ -0,0 +1,158 @@
+/*
+ * ***** 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/operators/bmo_planar_faces.c
+ * \ingroup bmesh
+ *
+ * Iternatively flatten 4+ sided faces.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_ghash.h"
+
+#include "bmesh.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+#define ELE_VERT_ADJUST (1 << 0)
+#define ELE_FACE_ADJUST (1 << 1)
+
+struct VertAccum {
+ float co[3];
+ int co_tot;
+};
+
+void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
+{
+ const float fac = BMO_slot_float_get(op->slots_in, "factor");
+ const int iterations = BMO_slot_int_get(op->slots_in, "iterations");
+ const int faces_num = BMO_slot_buffer_count(op->slots_in, "faces");
+
+ const float eps = 0.00001f;
+ const float eps_sq = SQUARE(eps);
+
+ BMOIter oiter;
+ BMFace *f;
+ BLI_mempool *vert_accum_pool;
+ GHash *vaccum_map;
+ float (*faces_center)[3];
+ int i, iter_step, shared_vert_num;
+
+ faces_center = MEM_mallocN(sizeof(*faces_center) * faces_num, __func__);
+
+ shared_vert_num = 0;
+ BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) {
+ BMLoop *l_iter, *l_first;
+
+ if (f->len == 3) {
+ continue;
+ }
+
+ BM_face_calc_center_mean_weighted(f, faces_center[i]);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
+ BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
+ shared_vert_num += 1;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ }
+
+ vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP);
+ vaccum_map = BLI_ghash_ptr_new_ex(__func__, shared_vert_num);
+
+ for (iter_step = 0; iter_step < iterations; iter_step++) {
+ GHashIterator gh_iter;
+ bool changed = false;
+
+ BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) {
+ BMLoop *l_iter, *l_first;
+ float plane[4];
+
+ if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) {
+ continue;
+ }
+ BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST);
+
+ BLI_assert(f->len != 3);
+
+ /* keep original face data (else we 'move' the face) */
+#if 0
+ BM_face_normal_update(f);
+ BM_face_calc_center_mean_weighted(f, f_center);
+#endif
+
+ plane_from_point_normal_v3(plane, faces_center[i], f->no);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ struct VertAccum *va;
+ void **va_p;
+ float co[3];
+
+ if (!BLI_ghash_ensure_p(vaccum_map, l_iter->v, &va_p)) {
+ *va_p = BLI_mempool_calloc(vert_accum_pool);
+ }
+ va = *va_p;
+
+ closest_to_plane_v3(co, plane, l_iter->v->co);
+ va->co_tot += 1;
+
+ interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ GHASH_ITER (gh_iter, vaccum_map) {
+ BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+ struct VertAccum *va = BLI_ghashIterator_getValue(&gh_iter);
+ BMIter iter;
+
+ if (len_squared_v3v3(v->co, va->co) > eps_sq) {
+ BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST);
+ interp_v3_v3v3(v->co, v->co, va->co, fac);
+ changed = true;
+ }
+
+ /* tag for re-calculation */
+ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+ if (f->len != 3) {
+ BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST);
+ }
+ }
+ }
+
+ /* if nothing changed, break out early */
+ if (changed == false) {
+ break;
+ }
+
+ BLI_ghash_clear(vaccum_map, NULL, NULL);
+ BLI_mempool_clear(vert_accum_pool);
+ }
+
+ MEM_freeN(faces_center);
+ BLI_ghash_free(vaccum_map, NULL, NULL);
+ BLI_mempool_destroy(vert_accum_pool);
+}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 871bee64c19..42373ad0ef0 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -29,9 +29,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
-#include "BLI_array.h"
#include "BLI_alloca.h"
#include "BLI_stackdefines.h"
+#include "BLI_stack.h"
#include "BKE_customdata.h"
@@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, e, EDGE_COL);
}
else if (!BM_edge_exists(v1, v2)) {
- BM_edge_create(bm, v1, v2, e, BM_CREATE_NO_DOUBLE);
+ BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
}
BMO_elem_flag_enable(bm, e, ELE_DEL);
@@ -261,7 +261,7 @@ void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op)
BMOIter siter;
BMIter iter;
BMVert *v, *vert_snap;
- BMLoop *l, *firstl = NULL;
+ BMLoop *l, *l_first = NULL;
float fac;
int i, tot;
@@ -273,33 +273,35 @@ void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op)
fac = 1.0f / tot;
BM_ITER_ELEM (l, &iter, vert_snap, BM_LOOPS_OF_VERT) {
- if (!firstl) {
- firstl = l;
+ if (l_first == NULL) {
+ l_first = l;
}
for (i = 0; i < bm->ldata.totlayer; i++) {
if (CustomData_layer_has_math(&bm->ldata, i)) {
- int type = bm->ldata.layers[i].type;
+ const int type = bm->ldata.layers[i].type;
+ const int offset = bm->ldata.layers[i].offset;
void *e1, *e2;
- e1 = CustomData_bmesh_get_layer_n(&bm->ldata, firstl->head.data, i);
- e2 = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+ e1 = BM_ELEM_CD_GET_VOID_P(l_first, offset);
+ e2 = BM_ELEM_CD_GET_VOID_P(l, offset);
CustomData_data_multiply(type, e2, fac);
- if (l != firstl)
+ if (l != l_first) {
CustomData_data_add(type, e1, e2);
+ }
}
}
}
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if (l == firstl) {
+ if (l == l_first) {
continue;
}
- CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, firstl->head.data, &l->head.data);
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_first->head.data, &l->head.data);
}
}
}
@@ -311,19 +313,20 @@ void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op)
BMVert *v;
BMLoop *l /* , *firstl = NULL */;
CDBlockBytes min, max;
- void *block;
- int i, type;
+ int i;
for (i = 0; i < bm->ldata.totlayer; i++) {
+ const int type = bm->ldata.layers[i].type;
+ const int offset = bm->ldata.layers[i].offset;
+
if (!CustomData_layer_has_math(&bm->ldata, i))
continue;
- type = bm->ldata.layers[i].type;
CustomData_data_initminmax(type, &min, &max);
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+ void *block = BM_ELEM_CD_GET_VOID_P(l, offset);
CustomData_data_dominmax(type, block, &min, &max);
}
}
@@ -334,7 +337,7 @@ void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op)
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
+ void *block = BM_ELEM_CD_GET_VOID_P(l, offset);
CustomData_data_copy_value(type, &min, block);
}
}
@@ -375,13 +378,14 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
BMOperator weldop;
BMWalker walker;
BMIter iter;
- BMEdge *e, **edges = NULL;
- BLI_array_declare(edges);
- float min[3], max[3], center[3];
- unsigned int i, tot;
+ BMEdge *e;
+ BLI_Stack *edge_stack;
BMOpSlot *slot_targetmap;
-
- BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
+
+ if (BMO_slot_bool_get(op->slots_in, "uvs")) {
+ BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
+ }
+
BMO_op_init(bm, &weldop, op->flag, "weld_verts");
slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
@@ -392,18 +396,20 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */
BMW_NIL_LAY);
+ 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];
BMVert *v_tar;
if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
continue;
- BLI_array_empty(edges);
+ BLI_assert(BLI_stack_is_empty(edge_stack));
INIT_MINMAX(min, max);
- for (e = BMW_begin(&walker, e->v1), tot = 0; e; e = BMW_step(&walker), tot++) {
- BLI_array_grow_one(edges);
- edges[tot] = e;
+ 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);
@@ -413,79 +419,90 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
}
- mid_v3_v3v3(center, min, max);
+ if (!BLI_stack_is_empty(edge_stack)) {
+
+ mid_v3_v3v3(center, min, max);
- /* snap edges to a point. for initial testing purposes anyway */
- v_tar = edges[0]->v1;
+ /* snap edges to a point. for initial testing purposes anyway */
+ e = *(BMEdge **)BLI_stack_peek(edge_stack);
+ v_tar = e->v1;
- for (i = 0; i < tot; i++) {
- unsigned int j;
+ while (!BLI_stack_is_empty(edge_stack)) {
+ unsigned int j;
+ BLI_stack_pop(edge_stack, &e);
- for (j = 0; j < 2; j++) {
- BMVert *v_src = *((&edges[i]->v1) + j);
+ for (j = 0; j < 2; j++) {
+ BMVert *v_src = *((&e->v1) + j);
- copy_v3_v3(v_src->co, center);
- if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
- BM_elem_flag_enable(v_src, BM_ELEM_TAG);
- BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar);
+ copy_v3_v3(v_src->co, center);
+ if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v_src, BM_ELEM_TAG);
+ BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar);
+ }
}
}
}
}
-
+
+ BLI_stack_free(edge_stack);
+
BMO_op_exec(bm, &weldop);
BMO_op_finish(bm, &weldop);
BMW_end(&walker);
- BLI_array_free(edges);
}
/* uv collapse function */
static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short oflag)
{
+ const int type = bm->ldata.layers[layer].type;
+ const int offset = bm->ldata.layers[layer].offset;
BMIter iter, liter;
BMFace *f;
BMLoop *l, *l2;
BMWalker walker;
- void **blocks = NULL;
- BLI_array_declare(blocks);
+ BLI_Stack *block_stack;
CDBlockBytes min, max;
- int i, tot, type = bm->ldata.layers[layer].type;
BMW_init(&walker, bm, BMW_LOOPDATA_ISLAND,
BMW_MASK_NOP, oflag, BMW_MASK_NOP,
BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */
layer);
+ block_stack = BLI_stack_new(sizeof(void *), __func__);
+
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
if (BMO_elem_flag_test(bm, l->e, oflag)) {
/* walk */
- BLI_array_empty(blocks);
+ BLI_assert(BLI_stack_is_empty(block_stack));
CustomData_data_initminmax(type, &min, &max);
- for (l2 = BMW_begin(&walker, l), tot = 0; l2; l2 = BMW_step(&walker), tot++) {
- BLI_array_grow_one(blocks);
- blocks[tot] = CustomData_bmesh_get_layer_n(&bm->ldata, l2->head.data, layer);
- CustomData_data_dominmax(type, blocks[tot], &min, &max);
+ for (l2 = BMW_begin(&walker, l); l2; l2 = BMW_step(&walker)) {
+ void *block = BM_ELEM_CD_GET_VOID_P(l2, offset);
+ CustomData_data_dominmax(type, block, &min, &max);
+ BLI_stack_push(block_stack, &block);
}
- if (tot) {
+ if (!BLI_stack_is_empty(block_stack)) {
CustomData_data_multiply(type, &min, 0.5f);
CustomData_data_multiply(type, &max, 0.5f);
CustomData_data_add(type, &min, &max);
/* snap CD (uv, vcol) points to their centroid */
- for (i = 0; i < tot; i++) {
- CustomData_data_copy_value(type, &min, blocks[i]);
+ while (!BLI_stack_is_empty(block_stack)) {
+ void *block;
+ BLI_stack_pop(block_stack, &block);
+ CustomData_data_copy_value(type, &min, block);
}
}
}
}
}
+ BLI_stack_free(block_stack);
+
BMW_end(&walker);
- BLI_array_free(blocks);
}
void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op)
@@ -519,8 +536,9 @@ void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op)
}
-static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op,
- BMOperator *optarget, BMOpSlot *optarget_slot)
+static void bmesh_find_doubles_common(
+ BMesh *bm, BMOperator *op,
+ BMOperator *optarget, BMOpSlot *optarget_slot)
{
BMVert **verts;
int verts_len;
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 003c27671a5..e3304298647 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -80,8 +80,9 @@ static void bmo_subd_init_shape_info(BMesh *bm, SubDParams *params)
}
-typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts,
- const SubDParams *params);
+typedef void (*subd_pattern_fill_fp)(
+ BMesh *bm, BMFace *face, BMVert **verts,
+ const SubDParams *params);
/*
* note: this is a pattern-based edge subdivider.
@@ -163,10 +164,11 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
return NULL;
}
/* calculates offset for co, based on fractal, sphere or smooth settings */
-static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc,
- BMVert *vsta, BMVert *vend)
+static void alter_co(
+ BMVert *v, BMEdge *UNUSED(e_orig),
+ const SubDParams *params, const float perc,
+ const BMVert *v_a, const BMVert *v_b)
{
- float tvec[3], fac;
float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
int i;
@@ -178,28 +180,26 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
}
else if (params->use_smooth) {
/* we calculate an offset vector vec1[], to be added to *co */
- float len, nor[3], nor1[3], nor2[3], val;
+ float dir[3], tvec[3];
+ float fac, len, val;
- sub_v3_v3v3(nor, vsta->co, vend->co);
- len = 0.5f * normalize_v3(nor);
-
- copy_v3_v3(nor1, vsta->no);
- copy_v3_v3(nor2, vend->no);
+ sub_v3_v3v3(dir, v_a->co, v_b->co);
+ len = M_SQRT1_2 * normalize_v3(dir);
/* cosine angle */
- fac = dot_v3v3(nor, nor1);
- mul_v3_v3fl(tvec, nor1, fac);
+ fac = dot_v3v3(dir, v_a->no);
+ mul_v3_v3fl(tvec, v_a->no, fac);
/* cosine angle */
- fac = -dot_v3v3(nor, nor2);
- madd_v3_v3fl(tvec, nor2, fac);
+ fac = -dot_v3v3(dir, v_b->no);
+ madd_v3_v3fl(tvec, v_b->no, fac);
/* falloff for multi subdivide */
val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
val = bmesh_subd_falloff_calc(params->smooth_falloff, val);
if (params->use_smooth_even) {
- val *= BM_vert_calc_shell_factor(v);
+ val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
}
mul_v3_fl(tvec, params->smooth * val * len);
@@ -208,12 +208,13 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
}
if (params->use_fractal) {
- const float len = len_v3v3(vsta->co, vend->co);
- float normal[3], co2[3], base1[3], base2[3];
+ float normal[3], co2[3], base1[3], base2[3], tvec[3];
+ const float len = len_v3v3(v_a->co, v_b->co);
+ float fac;
fac = params->fractal * len;
- mid_v3_v3v3(normal, vsta->no, vend->no);
+ mid_v3_v3v3(normal, v_a->no, v_b->no);
ortho_basis_v3v3_v3(base1, base2, normal);
add_v3_v3v3(co2, v->co, params->fractal_ofs);
@@ -234,9 +235,12 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
* this by getting the normals and coords for each shape key and
* re-calculate the smooth value for each but this is quite involved.
* for now its ok to simply apply the difference IMHO - campbell */
- sub_v3_v3v3(tvec, v->co, co);
if (params->shape_info.totlayer > 1) {
+ float tvec[3];
+
+ sub_v3_v3v3(tvec, v->co, co);
+
/* skip the last layer since its the temp */
i = params->shape_info.totlayer - 1;
co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
@@ -250,19 +254,21 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
/* assumes in the edge is the correct interpolated vertices already */
/* percent defines the interpolation, rad and flag are for special options */
/* results in new vertex with correct coordinate, vertex normal and weight group info */
-static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge,
- const SubDParams *params, float percent,
- float percent2,
- BMEdge **out, BMVert *vsta, BMVert *vend)
+static BMVert *bm_subdivide_edge_addvert(
+ BMesh *bm, BMEdge *edge, BMEdge *e_orig,
+ const SubDParams *params,
+ const float factor_edge_split, const float factor_subd,
+ BMVert *v_a, BMVert *v_b,
+ BMEdge **r_edge)
{
- BMVert *ev;
+ BMVert *v_new;
- ev = BM_edge_split(bm, edge, edge->v1, out, percent);
+ v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
- BMO_elem_flag_enable(bm, ev, ELE_INNER);
+ BMO_elem_flag_enable(bm, v_new, ELE_INNER);
/* offset for smooth or sphere or fractal */
- alter_co(ev, oedge, params, percent2, vsta, vend);
+ alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
#if 0 //BMESH_TODO
/* clip if needed by mirror modifier */
@@ -279,35 +285,40 @@ static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge,
}
#endif
- interp_v3_v3v3(ev->no, vsta->no, vend->no, percent2);
- normalize_v3(ev->no);
+ interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd);
+ normalize_v3(v_new->no);
- return ev;
+ return v_new;
}
-static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge,
- int curpoint, int totpoint, const SubDParams *params,
- BMEdge **newe, BMVert *vsta, BMVert *vend)
+static BMVert *subdivide_edge_num(
+ BMesh *bm, BMEdge *edge, BMEdge *e_orig,
+ int curpoint, int totpoint, const SubDParams *params,
+ BMVert *v_a, BMVert *v_b,
+ BMEdge **r_edge)
{
- BMVert *ev;
- float percent, percent2 = 0.0f;
+ BMVert *v_new;
+ float factor_edge_split, factor_subd;
if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
- percent = BMO_slot_map_float_get(params->slot_edge_percents, edge);
+ factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
+ factor_subd = 0.0f;
}
else {
- percent = 1.0f / (float)(totpoint + 1 - curpoint);
- percent2 = (float)(curpoint + 1) / (float)(totpoint + 1);
-
+ factor_edge_split = 1.0f / (float)(totpoint + 1 - curpoint);
+ factor_subd = (float)(curpoint + 1) / (float)(totpoint + 1);
}
- ev = bm_subdivide_edge_addvert(bm, edge, oedge, params, percent,
- percent2, newe, vsta, vend);
- return ev;
+ v_new = bm_subdivide_edge_addvert(
+ bm, edge, e_orig, params,
+ factor_edge_split, factor_subd,
+ v_a, v_b, r_edge);
+ return v_new;
}
-static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *params,
- BMVert *vsta, BMVert *vend)
+static void bm_subdivide_multicut(
+ BMesh *bm, BMEdge *edge, const SubDParams *params,
+ BMVert *v_a, BMVert *v_b)
{
BMEdge *eed = edge, *e_new, e_tmp = *edge;
BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2;
@@ -317,7 +328,7 @@ static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *par
e_tmp.v2 = &v2_tmp;
for (i = 0; i < numcuts; i++) {
- v = subdivideedgenum(bm, eed, &e_tmp, i, params->numcuts, params, &e_new, vsta, vend);
+ v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
@@ -434,7 +445,7 @@ static void quad_2edge_split_innervert(BMesh *bm, BMFace *UNUSED(face), BMVert *
e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
e_tmp = *e;
- v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, &e_new, e->v1, e->v2);
+ v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new);
if (i != numcuts - 1) {
connect_smallest_face(bm, v_last, v, &f_new);
@@ -577,8 +588,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
e_tmp = *e;
for (a = 0; a < numcuts; a++) {
- v = subdivideedgenum(bm, e, &e_tmp, a, numcuts, params, &e_new,
- v1, v2);
+ v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new);
BMESH_ASSERT(v != NULL);
@@ -685,8 +695,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
e_tmp.v1 = &v1_tmp;
e_tmp.v2 = &v2_tmp;
for (j = 0; j < i; j++) {
- v = subdivideedgenum(bm, e, &e_tmp, j, i, params, &e_new,
- verts[a], verts[b]);
+ v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
lines[i + 1][j + 1] = v;
BMO_elem_flag_enable(bm, e_new, ELE_INNER);
@@ -1168,14 +1177,15 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
/* editmesh-emulating function */
-void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag,
- const float smooth, const short smooth_falloff, const bool use_smooth_even,
- const float fractal, const float along_normal,
- const int numcuts,
- const int seltype, const int cornertype,
- const short use_single_edge, const short use_grid_fill,
- const short use_only_quads,
- const int seed)
+void BM_mesh_esubdivide(
+ BMesh *bm, const char edge_hflag,
+ const float smooth, const short smooth_falloff, const bool use_smooth_even,
+ const float fractal, const float along_normal,
+ const int numcuts,
+ const int seltype, const int cornertype,
+ const short use_single_edge, const short use_grid_fill,
+ const short use_only_quads,
+ const int seed)
{
BMOperator op;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index c01ad10d716..0e619b4cece 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -80,8 +80,9 @@ static unsigned int bm_verts_tag_count(BMesh *bm)
}
#endif
-static float bezier_handle_calc_length_v3(const float co_a[3], const float no_a[3],
- const float co_b[3], const float no_b[3])
+static float bezier_handle_calc_length_v3(
+ const float co_a[3], const float no_a[3],
+ const float co_b[3], const float no_b[3])
{
const float dot = dot_v3v3(no_a, no_b);
/* gives closest approx at a circle with 2 parallel handles */
@@ -538,12 +539,13 @@ static void bm_edgering_pair_store_free(
/* -------------------------------------------------------------------- */
/* Interpolation Function */
-static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- ListBase *eloops_ring,
- const int interp_mode, const int cuts, const float smooth,
- const float *falloff_cache)
+static void bm_edgering_pair_interpolate(
+ BMesh *bm, LoopPairStore *lpair,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ ListBase *eloops_ring,
+ const int interp_mode, const int cuts, const float smooth,
+ const float *falloff_cache)
{
const int resolu = cuts + 2;
const int dims = 3;
@@ -878,9 +880,10 @@ static bool bm_edgering_pair_order_is_flipped(BMesh *UNUSED(bm),
* Takes 2 edge loops that share edges,
* sort their verts and rotates the list so the lined up.
*/
-static void bm_edgering_pair_order(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b)
+static void bm_edgering_pair_order(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b)
{
ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
@@ -951,11 +954,12 @@ static void bm_edgering_pair_order(BMesh *bm,
*
* \note loops are _not_ aligned.
*/
-static void bm_edgering_pair_subdiv(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- ListBase *eloops_ring,
- const int cuts)
+static void bm_edgering_pair_subdiv(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ ListBase *eloops_ring,
+ const int cuts)
{
ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
// ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
@@ -1043,11 +1047,12 @@ static void bm_edgering_pair_subdiv(BMesh *bm,
bm_edgeloop_vert_tag(el_store_b, false);
}
-static void bm_edgering_pair_ringsubd(BMesh *bm, LoopPairStore *lpair,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- const int interp_mode, const int cuts, const float smooth,
- const float *falloff_cache)
+static void bm_edgering_pair_ringsubd(
+ BMesh *bm, LoopPairStore *lpair,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ const int interp_mode, const int cuts, const float smooth,
+ const float *falloff_cache)
{
ListBase eloops_ring = {NULL};
bm_edgering_pair_order(bm, el_store_a, el_store_b);
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index da1991a187d..964d0b1dfc6 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -208,7 +208,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
found = true;
break;
}
@@ -221,7 +221,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMO_elem_flag_enable(bm, e, SEL_FLAG);
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
@@ -232,7 +232,7 @@ static void bmo_region_extend_expand(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
}
}
@@ -243,7 +243,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMO_elem_flag_enable(bm, e, SEL_FLAG);
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
@@ -267,7 +267,9 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
+ {
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
}
}
@@ -277,7 +279,9 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
+ {
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 990a2108bd7..19fe492c670 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -274,11 +274,12 @@ BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const
}
/* recalc an edge in the heap (surrounding geometry has changed) */
-static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- /* only for testing the edge is in the array */
- const BMEdge **edge_array, const int edge_array_len,
+static void bm_edge_update_beauty_cost_single(
+ BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
+ /* only for testing the edge is in the array */
+ const BMEdge **edge_array, const int edge_array_len,
- const short flag, const short method)
+ const short flag, const short method)
{
if (edge_in_array(e, edge_array, edge_array_len)) {
const int i = BM_elem_index_get(e);
@@ -316,10 +317,11 @@ static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode *
}
/* we have rotated an edge, tag other edges and clear this one */
-static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- const BMEdge **edge_array, const int edge_array_len,
- /* only for testing the edge is in the array */
- const short flag, const short method)
+static void bm_edge_update_beauty_cost(
+ BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
+ const BMEdge **edge_array, const int edge_array_len,
+ /* only for testing the edge is in the array */
+ const short flag, const short method)
{
int i;
@@ -333,7 +335,7 @@ static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_
BLI_assert(e->l->f->len == 3 &&
e->l->radial_next->f->len == 3);
- BLI_assert(BM_edge_face_count(e) == 2);
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
for (i = 0; i < 4; i++) {
bm_edge_update_beauty_cost_single(
@@ -389,11 +391,11 @@ void BM_mesh_beautify_fill(
i = BM_elem_index_get(e);
eheap_table[i] = NULL;
- BLI_assert(BM_edge_face_count(e) == 2);
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
- BLI_assert(e == NULL || BM_edge_face_count(e) == 2);
+ BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
if (LIKELY(e)) {
GSet *e_state_set = edge_state_arr[i];
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 3c7a86a332f..3348afa3bfa 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -57,6 +57,9 @@
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
+/* will likely remove the code enabled by this soon, when sure that it is not needed */
+// #define PRE_275_ALGORITHM
+
/* for testing */
// #pragma GCC diagnostic error "-Wpadded"
@@ -187,7 +190,7 @@ typedef struct BevelParams {
bool limit_offset; /* should offsets be limited by collisions? */
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
- int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
+ int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -244,8 +247,9 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert
BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
}
-static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto,
- int ifrom, int jfrom, int kfrom)
+static void copy_mesh_vert(
+ VMesh *vm, int ito, int jto, int kto,
+ int ifrom, int jfrom, int kfrom)
{
NewVert *nvto, *nvfrom;
@@ -361,8 +365,9 @@ static BMFace *boundvert_rep_face(BoundVert *v)
*
* \note ALL face creation goes through this function, this is important to keep!
*/
-static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
- BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
+static BMFace *bev_create_ngon(
+ BMesh *bm, BMVert **vert_arr, const int totv,
+ BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
{
BMIter iter;
BMLoop *l;
@@ -402,15 +407,17 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
return f;
}
-static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *facerep, int mat_nr, bool do_interp)
+static BMFace *bev_create_quad_tri(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ BMFace *facerep, int mat_nr, bool do_interp)
{
BMVert *varr[4] = {v1, v2, v3, v4};
return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, mat_nr, do_interp);
}
-static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
+static BMFace *bev_create_quad_tri_ex(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
{
BMVert *varr[4] = {v1, v2, v3, v4};
BMFace *farr[4] = {f1, f2, f3, f4};
@@ -419,8 +426,9 @@ static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
-static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2,
- int layer_index)
+static bool contig_ldata_across_loops(
+ BMesh *bm, BMLoop *l1, BMLoop *l2,
+ int layer_index)
{
const int offset = bm->ldata.layers[layer_index].offset;
const int type = bm->ldata.layers[layer_index].type;
@@ -478,7 +486,9 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
return true;
}
-/* Like bev_create_quad_tri, but when verts straddle an old edge.
+/**
+ * Like bev_create_quad_tri, but when verts straddle an old edge.
+ * <pre>
* e
* |
* v1+---|---+v4
@@ -487,13 +497,16 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
* v2+---|---+v3
* |
* f1 | f2
+ * </pre>
*
* Most CustomData for loops can be interpolated in their respective
* faces' loops, but for UVs and other 'has_math_cd' layers, only
* do this if the UVs are continuous across the edge e, otherwise pick
* one side (f1, arbitrarily), and interpolate them all on that side.
- * For face data, use f1 (arbitrarily) as face representative. */
-static BMFace *bev_create_quad_straddle(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ * For face data, use f1 (arbitrarily) as face representative.
+ */
+static BMFace *bev_create_quad_straddle(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
BMFace *f1, BMFace *f2, int mat_nr, bool is_seam)
{
BMFace *f, *facerep;
@@ -582,10 +595,42 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
}
}
+/* co should be approximately on the plane between e1 and e2, which share common vert v
+ * and common face f (which cannot be NULL).
+ * Is it between those edges, sweeping CCW? */
+static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2)
+{
+ BMVert *v1, *v2;
+ float dir1[3], dir2[3], dirco[3], no[3];
+ float ang11, ang1co;
+
+ v1 = BM_edge_other_vert(e1->e, v);
+ v2 = BM_edge_other_vert(e2->e, v);
+ sub_v3_v3v3(dir1, v->co, v1->co);
+ sub_v3_v3v3(dir2, v->co, v2->co);
+ sub_v3_v3v3(dirco, v->co, co);
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dirco);
+ ang11 = angle_normalized_v3v3(dir1, dir2);
+ ang1co = angle_normalized_v3v3(dir1, dirco);
+ /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
+ cross_v3_v3v3(no, dir1, dir2);
+ if (dot_v3v3(no, f->no) < 0.0f)
+ ang11 = (float)(M_PI * 2.0) - ang11;
+ cross_v3_v3v3(no, dir1, dirco);
+ if (dot_v3v3(no, f->no) < 0.0f)
+ ang1co = (float)(M_PI * 2.0) - ang1co;
+ return (ang11 - ang1co > -BEVEL_EPSILON_BIG);
+}
+
/*
* Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco.
* e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of
* the bevel vertex, e1 precedes e2 in CCW order.
+ * Except: if edges_between is true, there are edges between e1 and e2 in CCW order so they
+ * don't share a common face. We want the meeting point to be on an existing face so it
+ * should be dropped onto one of the intermediate faces, if possible.
* Offset edge is on right of both edges, where e1 enters v and e2 leave it.
* When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2),
* but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may
@@ -594,16 +639,27 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
* record the change in offset_l (or offset_r); later we can tell that a change has happened because
* the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*/
-static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float meetco[3])
+static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
{
- float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3],
- off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], ang, d;
+ float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3],
+ norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3],
+ isect2[3], dropco[3], plane[4], ang, d;
BMVert *closer_v;
+ EdgeHalf *e, *e1next, *e2prev;
+ BMFace *ff;
+ int isect_kind;
/* get direction vectors for two offset lines */
sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
+ if (edges_between) {
+ e1next = e1->next;
+ e2prev = e2->prev;
+ sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
+ sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
+ }
+
ang = angle_v3v3(dir1, dir2);
if (ang < BEVEL_EPSILON_BIG) {
/* special case: e1 and e2 are parallel; put offset point perp to both, from v.
@@ -643,14 +699,31 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
* If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
* Use f->no to figure out which side to look at angle from, as even if
* f is non-planar, will be more accurate than vertex normal */
- cross_v3_v3v3(norm_v, dir2, dir1);
- normalize_v3(norm_v);
- if (dot_v3v3(norm_v, f ? f->no : v->no) < 0.0f)
- negate_v3(norm_v);
+ if (!edges_between) {
+ cross_v3_v3v3(norm_v1, dir2, dir1);
+ normalize_v3(norm_v1);
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v1);
+ copy_v3_v3(norm_v2, norm_v1);
+ }
+ else {
+ /* separate faces; get face norms at corners for each separately */
+ cross_v3_v3v3(norm_v1, dir1n, dir1);
+ normalize_v3(norm_v1);
+ f = e1->fnext;
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v1);
+ cross_v3_v3v3(norm_v2, dir2, dir2p);
+ normalize_v3(norm_v2);
+ f = e2->fprev;
+ if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v2);
+ }
+
/* get vectors perp to each edge, perp to norm_v, and pointing into face */
- cross_v3_v3v3(norm_perp1, dir1, norm_v);
- cross_v3_v3v3(norm_perp2, dir2, norm_v);
+ cross_v3_v3v3(norm_perp1, dir1, norm_v1);
+ cross_v3_v3v3(norm_perp2, dir2, norm_v2);
normalize_v3(norm_perp1);
normalize_v3(norm_perp2);
@@ -662,11 +735,10 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
add_v3_v3v3(off2b, off2a, dir2);
- /* intersect the lines; by construction they should be on the same plane and not parallel */
- if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) {
-#ifdef BEVEL_ASSERT_PROJECT
- BLI_assert(!"offset_meet failure");
-#endif
+ /* intersect the lines */
+ isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
+ if (isect_kind == 0) {
+ /* lines are colinear: we already tested for this, but this used a different epsilon */
copy_v3_v3(meetco, off1a); /* just to do something */
d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
@@ -686,15 +758,38 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
copy_v3_v3(meetco, closer_v->co);
e1->offset_r = len_v3v3(meetco, v->co);
}
+ if (edges_between && e1->offset_r > 0.0 && e2->offset_l > 0.0) {
+ /* Try to drop meetco to a face between e1 and e2 */
+ if (isect_kind == 2) {
+ /* lines didn't meet in 3d: get average of meetco and isect2 */
+ mid_v3_v3v3(meetco, meetco, isect2);
+ }
+ for (e = e1; e != e2; e = e->next) {
+ ff = e->fnext;
+ if (!ff)
+ continue;
+ plane_from_point_normal_v3(plane, v->co, ff->no);
+ closest_to_plane_v3(dropco, plane, meetco);
+ if (point_between_edges(dropco, v, ff, e, e->next)) {
+ copy_v3_v3(meetco, dropco);
+ break;
+ }
+ }
+ e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
+ e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
+ }
}
}
}
+/* chosen so that 1/sin(BEVEL_GOOD_ANGLE) is about 4, giving that expansion factor to bevel width */
+#define BEVEL_GOOD_ANGLE 0.25f
+
/* Calculate the meeting point between e1 and e2 (one of which should have zero offsets),
* where e1 precedes e2 in CCW order around their common vertex v (viewed from normal side).
* If r_angle is provided, return the angle between e and emeet in *r_angle.
* If the angle is 0, or it is 180 degrees or larger, there will be no meeting point;
- * return false in that case, else true */
+ * return false in that case, else true. */
static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetco[3], float *r_angle)
{
float dir1[3], dir2[3], fno[3], ang, sinang;
@@ -706,7 +801,7 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
/* find angle from dir1 to dir2 as viewed from vertex normal side */
ang = angle_normalized_v3v3(dir1, dir2);
- if (ang < BEVEL_EPSILON) {
+ if (fabsf(ang) < BEVEL_GOOD_ANGLE) {
if (r_angle)
*r_angle = 0.0f;
return false;
@@ -717,10 +812,11 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
if (r_angle)
*r_angle = ang;
- if (ang - (float)M_PI > BEVEL_EPSILON)
+ if (fabsf(ang - (float)M_PI) < BEVEL_GOOD_ANGLE)
return false;
sinang = sinf(ang);
+
copy_v3_v3(meetco, v->co);
if (e1->offset_r == 0.0f)
madd_v3_v3fl(meetco, dir1, e2->offset_l / sinang);
@@ -729,6 +825,17 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
return true;
}
+/* Return true if it will look good to put the meeting point where offset_on_edge_between
+ * would put it. This means that neither side sees a reflex angle */
+static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v)
+{
+ float ang;
+ float meet[3];
+
+ return offset_meet_edge(e1, emid, v, meet, &ang) &&
+ offset_meet_edge(emid, e2, v, meet, &ang);
+}
+
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
* on the in-between edge emid. Viewed from the vertex normal side, the CCW
* order of these edges is e1, emid, e2.
@@ -737,8 +844,9 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
* already, prefer to keep the offset the same on this end.
* Otherwise, pick a point between the two intersection points on emid that minimizes
* the sum of squares of errors from desired offset. */
-static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3])
+static void offset_on_edge_between(
+ BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3])
{
float d, ang1, ang2, sina1, sina2, lambda;
float meet1[3], meet2[3];
@@ -787,14 +895,16 @@ static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2,
e2->offset_l = d;
}
+#ifdef PRE_275_ALGORITHM
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
* when there is an in-between edge emid, and we prefer to have a point that may not
* be on emid if that does a better job of keeping offsets at the user spec.
* Viewed from the vertex normal side, the CCW order of the edges is e1, emid, e2.
* The offset lines may not meet exactly: the lines may be angled so that they can't meet.
* In that case, pick the offset_on_edge_between. */
-static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3])
+static void offset_in_two_planes(
+ BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3])
{
float dir1[3], dir2[3], dirmid[3], norm_perp1[3], norm_perp2[3],
off1a[3], off1b[3], off2a[3], off2b[3], isect2[3],
@@ -861,6 +971,7 @@ static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, Ed
/* else iret == 1 and the lines are coplanar so meetco has the intersection */
}
}
+#endif
/* Offset by e->offset in plane with normal plane_no, on left if left==true,
* else on right. If no is NULL, choose an arbitrary plane different
@@ -1079,8 +1190,9 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f)
* and B has the right side as columns - both extended into homogeneous coords.
* So M = B*(Ainverse). Doing Ainverse by hand gives the code below.
*/
-static bool make_unit_square_map(const float va[3], const float vmid[3], const float vb[3],
- float r_mat[4][4])
+static bool make_unit_square_map(
+ const float va[3], const float vmid[3], const float vb[3],
+ float r_mat[4][4])
{
float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
@@ -1128,8 +1240,9 @@ static bool make_unit_square_map(const float va[3], const float vmid[3], const f
* and 1/2{va+vb+vc-vd}
* and Blender matrices have cols at m[i][*].
*/
-static void make_unit_cube_map(const float va[3], const float vb[3], const float vc[3],
- const float vd[3], float r_mat[4][4])
+static void make_unit_cube_map(
+ const float va[3], const float vb[3], const float vc[3],
+ const float vd[3], float r_mat[4][4])
{
copy_v3_v3(r_mat[0], va);
sub_v3_v3(r_mat[0], vb);
@@ -1410,6 +1523,325 @@ static void set_bound_vert_seams(BevVert *bv)
} while ((v = v->next) != bv->vmesh->boundstart);
}
+#ifndef PRE_275_ALGORITHM
+/* Is e between two planes where angle between is 180? */
+static bool eh_on_plane(EdgeHalf *e)
+{
+ float dot;
+
+ if (e->fprev && e->fnext) {
+ dot = dot_v3v3(e->fprev->no, e->fnext->no);
+ if (fabsf(dot) <= BEVEL_EPSILON ||
+ fabsf(dot - 1.0f) <= BEVEL_EPSILON)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Calculate the profiles for all the BoundVerts of VMesh vm */
+static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm)
+{
+ BoundVert *v;
+
+ v = vm->boundstart;
+ do {
+ set_profile_params(bp, bv, v);
+ calculate_profile(bp, v);
+ } while ((v = v->next) != vm->boundstart);
+}
+
+/* Implements build_boundary for vertex-only case */
+static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct)
+{
+ VMesh *vm = bv->vmesh;
+ EdgeHalf *efirst, *e;
+ BoundVert *v;
+ float co[3];
+
+ BLI_assert(bp->vertex_only);
+
+ e = efirst = &bv->edges[0];
+ do {
+ slide_dist(e, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(bp->mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ } while ((e = e->next) != efirst);
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+ if (vm->count == 2)
+ vm->mesh_kind = M_NONE;
+ else if (bp->seg == 1)
+ vm->mesh_kind = M_POLY;
+ else
+ vm->mesh_kind = M_ADJ;
+ }
+}
+
+/* Special case of build_boundary when a single edge is beveled.
+ * The 'width adjust' part of build_boundary has been done already, and
+ * efirst is the first beveled edge at vertex bv. */
+static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
+{
+ MemArena *mem_arena = bp->mem_arena;
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ EdgeHalf *e;
+ const float *no;
+ float co[3], d;
+
+ e = efirst;
+ if (bv->edgecount == 2) {
+ /* only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge */
+ no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL);
+ offset_in_plane(e, no, true, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = v->ebev = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL);
+ offset_in_plane(e, no, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ /* make artifical extra point along unbeveled edge, and form triangle */
+ slide_dist(e->next, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e->next;
+ e->next->leftv = e->next->rightv = v;
+ /* could use M_POLY too, but tri-fan looks nicer)*/
+ vm->mesh_kind = M_TRI_FAN;
+ set_bound_vert_seams(bv);
+ }
+ else {
+ adjust_bound_vert(e->next->leftv, co);
+ }
+ }
+ else {
+ /* More than 2 edges in. Put on-edge verts on all the other edges
+ * and join with the beveled edge to make a poly or adj mesh,
+ * Because e->prev has offset 0, offset_meet will put co on that edge */
+ /* TODO: should do something else if angle between e and e->prev > 180 */
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = v->ebev = e;
+ e->leftv = v;
+ e->prev->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ e = e->next;
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = e;
+ e->leftv = v;
+ e->prev->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ d = len_v3v3(bv->v->co, co);
+ for (e = e->next; e->next != efirst; e = e->next) {
+ slide_dist(e, bv->v, d, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ }
+ }
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (bv->edgecount >= 3) {
+ /* special case: snap profile to plane of adjacent two edges */
+ v = vm->boundstart;
+ BLI_assert(v->ebev != NULL);
+ move_profile_plane(v, v->efirst, v->next->elast);
+ calculate_profile(bp, v);
+ }
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+
+ if (vm->count == 2 && bv->edgecount == 3) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (vm->count == 3) {
+ vm->mesh_kind = M_TRI_FAN;
+ }
+ else {
+ vm->mesh_kind = M_POLY;
+ }
+ }
+}
+
+/* Make a circular list of BoundVerts for bv, each of which has the coordinates
+ * of a vertex on the boundary of the beveled vertex bv->v.
+ * This may adjust some EdgeHalf widths, and there might have to be
+ * a subsequent pass to make the widths as consistent as possible.
+ * The first time through, construct will be true and we are making the BoundVerts
+ * and setting up the BoundVert and EdgeHalf pointers appropriately.
+ * For a width consistency path, we just recalculate the coordinates of the
+ * BoundVerts. If the other ends have been (re)built already, then we
+ * copy the offsets from there to match, else we use the ideal (user-specified)
+ * widths.
+ * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
+ * Doesn't make the actual BMVerts */
+static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
+{
+ MemArena *mem_arena = bp->mem_arena;
+ EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother;
+ BoundVert *v;
+ BevVert *bvother;
+ VMesh *vm;
+ float co[3];
+ int nip, nnip;
+
+ /* Current bevel does nothing if only one edge into a vertex */
+ if (bv->edgecount <= 1)
+ return;
+
+ if (bp->vertex_only) {
+ build_boundary_vertex_only(bp, bv, construct);
+ return;
+ }
+
+ vm = bv->vmesh;
+
+ /* Find a beveled edge to be efirst. Then for each edge, try matching widths to other end. */
+ e = efirst = next_bev(bv, NULL);
+ BLI_assert(e->is_bev);
+ do {
+ eother = find_other_end_edge_half(bp, e, &bvother);
+ if (eother && bvother->visited && bp->offset_type != BEVEL_AMT_PERCENT) {
+ /* try to keep bevel even by matching other end offsets */
+ e->offset_l = eother->offset_r;
+ e->offset_r = eother->offset_l;
+ }
+ else {
+ /* reset to user spec */
+ e->offset_l = e->offset_l_spec;
+ e->offset_r = e->offset_r_spec;
+ }
+ } while ((e = e->next) != efirst);
+
+ if (bv->selcount == 1) {
+ /* special case: only one beveled edge in */
+ build_boundary_terminal_edge(bp, bv, efirst, construct);
+ return;
+ }
+
+ /* Here: there is more than one beveled edge.
+ * We make BoundVerts to connect the sides of the beveled edges.
+ * Non-beveled edges in between will just join to the appropriate juncture point. */
+ e = efirst;
+ do {
+ BLI_assert(e->is_bev);
+ /* Make the BoundVert for the right side of e; other side will be made
+ * when the beveled edge to the left of e is handled.
+ * Analyze edges until next beveled edge.
+ * They are either "in plane" (preceding and subsequent faces are coplanar)
+ * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
+ * along one of those if possible. */
+ nip = nnip = 0; /* counts of in-plane / not-in-plane */
+ enip = eip = NULL; /* representatives of each */
+ for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
+ if (eh_on_plane(e2)) {
+ nip++;
+ eip = e2;
+ }
+ else {
+ nnip++;
+ enip = e2;
+ }
+ }
+ if (nip == 0 && nnip == 0) {
+ offset_meet(e, e2, bv->v, e->fnext, false, co);
+ }
+ else if (nnip > 0) {
+ if (nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
+ offset_on_edge_between(bp, e, e2, enip, bv->v, co);
+ }
+ else {
+ offset_meet(e, e2, bv->v, NULL, true, co);
+ }
+ }
+ else {
+ /* nip > 0 and nnip == 0 */
+ if (nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) {
+ offset_on_edge_between(bp, e, e2, eip, bv->v, co);
+ }
+ else {
+ offset_meet(e, e2, bv->v, NULL, true, co);
+ }
+ }
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e;
+ v->elast = e2;
+ v->ebev = e2;
+ e->rightv = v;
+ e2->leftv = v;
+ for (e3 = e->next; e3 != e2; e3 = e3->next) {
+ e3->leftv = e3->rightv = v;
+ }
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ e = e2;
+ } while (e != efirst);
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+
+ if (vm->count == 2) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (efirst->seg == 1) {
+ vm->mesh_kind = M_POLY;
+ }
+ else {
+ vm->mesh_kind = M_ADJ;
+ }
+ }
+}
+#endif
+
+#ifdef PRE_275_ALGORITHM
+/* This code was used prior to just before the 2.75 Blender release.
+ * It treated multiple non-beveled edges between beveled ones differently */
+
/* Make a circular list of BoundVerts for bv, each of which has the coordinates
* of a vertex on the boundary of the beveled vertex bv->v.
* This may adjust some EdgeHalf widths, and there might have to be
@@ -1504,7 +1936,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
/* handle only left side of beveled edge e here: next iteration should do right side */
if (e->prev->is_bev) {
BLI_assert(e->prev != e); /* see: wire edge special case */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1541,7 +1973,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
else {
/* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1565,7 +1997,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
else if (e->prev->is_bev) {
/* on-edge meet between e->prev and e */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1642,6 +2074,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
}
+#endif
/* Do a global pass to try to make offsets as even as possible.
* Consider this graph:
@@ -1861,9 +2294,10 @@ static void vmesh_center(VMesh *vm, float r_cent[3])
}
}
-static void avg4(float co[3],
- const NewVert *v0, const NewVert *v1,
- const NewVert *v2, const NewVert *v3)
+static void avg4(
+ float co[3],
+ const NewVert *v0, const NewVert *v1,
+ const NewVert *v2, const NewVert *v3)
{
add_v3_v3v3(co, v0->co, v1->co);
add_v3_v3(co, v2->co);
@@ -2778,7 +3212,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k);
}
- if (BM_vert_face_count(bv->v) == 0) {
+ if (BM_vert_face_check(bv->v) == false) {
e_eg = bv->edges[0].e;
BLI_assert(e_eg != NULL);
for (k = 0; k < ns; k++) {
@@ -3755,10 +4189,11 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
*
* \warning all tagged edges _must_ be manifold.
*/
-void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
- const float segments, const float profile,
- const bool vertex_only, const bool use_weights, const bool limit_offset,
- const struct MDeformVert *dvert, const int vertex_group, const int mat)
+void BM_mesh_bevel(
+ BMesh *bm, const float offset, const int offset_type,
+ const float segments, const float profile,
+ const bool vertex_only, const bool use_weights, const bool limit_offset,
+ const struct MDeformVert *dvert, const int vertex_group, const int mat)
{
BMIter iter;
BMVert *v, *v_next;
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 52d8faa5401..b4bb6c56b7d 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -29,9 +29,10 @@
struct MDeformVert;
-void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments,
- const float profile, const bool vertex_only, const bool use_weights,
- const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
- const int mat);
+void BM_mesh_bevel(
+ BMesh *bm, const float offset, const int offset_type, const float segments,
+ const float profile, const bool vertex_only, const bool use_weights,
+ const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
+ const int mat);
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index e6e33c905da..fbcf573acd9 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -106,7 +106,7 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
if (val_a > val_b) return 1;
else if (val_a < val_b) return -1;
- return 0;
+ else return 0;
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index a1b26990587..6415da9a0c2 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -27,21 +27,22 @@
* \ingroup bmesh
*/
-void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, const bool do_triangulate);
+void BM_mesh_decimate_collapse(
+ BMesh *bm, const float factor,
+ float *vweights, float vweight_factor,
+ const bool do_triangulate);
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
-void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out);
-void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit);
-
-/* these weights are accumulated so too high values may reach 'inf' too quickly */
-#define BM_MESH_DECIM_WEIGHT_MAX 100000.0f
-#define BM_MESH_DECIM_WEIGHT_EPS (1.0f / BM_MESH_DECIM_WEIGHT_MAX)
+void BM_mesh_decimate_dissolve_ex(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr, const int vinput_len,
+ BMEdge **einput_arr, const int einput_len,
+ const short oflag_out);
+void BM_mesh_decimate_dissolve(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit);
#endif /* __BMESH_DECIMATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 811a144fc39..c3533245d9b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -47,6 +47,12 @@
#define USE_TRIANGULATE
#define USE_VERT_NORMAL_INTERP /* has the advantage that flipped faces don't mess up vertex normals */
+/* if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */
+#define USE_TOPOLOGY_FALLBACK
+#ifdef USE_TOPOLOGY_FALLBACK
+# define TOPOLOGY_FALLBACK_EPS FLT_EPSILON
+#endif
+
/* these checks are for rare cases that we can't avoid since they are valid meshes still */
#define USE_SAFETY_CHECKS
@@ -77,12 +83,15 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
BMLoop *l_first;
BMLoop *l_iter;
- const float *co = BM_FACE_FIRST_LOOP(f)->v->co;
- const float *no = f->no;
- const float offset = -dot_v3v3(no, co);
+ float center[3];
+ double plane_db[4];
Quadric q;
- BLI_quadric_from_v3_dist(&q, no, offset);
+ BM_face_calc_center_mean(f, center);
+ copy_v3db_v3fl(plane_db, f->no);
+ plane_db[3] = -dot_v3db_v3fl(plane_db, center);
+
+ BLI_quadric_from_plane(&q, plane_db);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -94,14 +103,22 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (UNLIKELY(BM_edge_is_boundary(e))) {
float edge_vector[3];
- float edge_cross[3];
+ float edge_plane[3];
+ double edge_plane_db[4];
sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
f = e->l->f;
- cross_v3_v3v3(edge_cross, edge_vector, f->no);
- if (normalize_v3(edge_cross) > FLT_EPSILON) {
+ cross_v3_v3v3(edge_plane, edge_vector, f->no);
+ copy_v3db_v3fl(edge_plane_db, edge_plane);
+
+ if (normalize_v3_d(edge_plane_db) > FLT_EPSILON) {
Quadric q;
- BLI_quadric_from_v3_dist(&q, edge_cross, -dot_v3v3(edge_cross, e->v1->co));
+ float center[3];
+
+ mid_v3_v3v3(center, e->v1->co, e->v2->co);
+
+ edge_plane_db[3] = -dot_v3db_v3fl(edge_plane_db, center);
+ BLI_quadric_from_plane(&q, edge_plane_db);
BLI_quadric_mul(&q, BOUNDARY_PRESERVE_WEIGHT);
BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
@@ -112,18 +129,19 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
}
-static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3],
- const Quadric *vquadrics)
+static void bm_decim_calc_target_co(
+ BMEdge *e, float optimize_co[3],
+ const Quadric *vquadrics)
{
/* compute an edge contraction target for edge 'e'
* this is computed by summing it's vertices quadrics and
* optimizing the result. */
Quadric q;
- BLI_quadric_add_qu_ququ(&q,
- &vquadrics[BM_elem_index_get(e->v1)],
- &vquadrics[BM_elem_index_get(e->v2)]);
-
+ BLI_quadric_add_qu_ququ(
+ &q,
+ &vquadrics[BM_elem_index_get(e->v1)],
+ &vquadrics[BM_elem_index_get(e->v2)]);
if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
return; /* all is good */
@@ -162,13 +180,15 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
cross_v3_v3v3(cross_exist, vec_other, vec_exist);
cross_v3_v3v3(cross_optim, vec_other, vec_optim);
- /* normalize isn't really needed, but ensures the value at a unit we can compare against */
- normalize_v3(cross_exist);
- normalize_v3(cross_optim);
+ /* avoid normalize */
+ if (dot_v3v3(cross_exist, cross_optim) <=
+ (len_squared_v3(cross_exist) + len_squared_v3(cross_optim)) * 0.01f)
+ {
+ return true;
+ }
#else
normal_tri_v3(cross_exist, v->co, co_prev, co_next);
normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
-#endif
/* use a small value rather then zero so we don't flip a face in multiple steps
* (first making it zero area, then flipping again) */
@@ -176,6 +196,8 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
//printf("no flip\n");
return true;
}
+#endif
+
}
}
}
@@ -183,9 +205,29 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
return false;
}
-static void bm_decim_build_edge_cost_single(BMEdge *e,
- const Quadric *vquadrics, const float *vweights,
- Heap *eheap, HeapNode **eheap_table)
+#ifdef USE_TOPOLOGY_FALLBACK
+/**
+ * when the cost is so small that its not useful (flat surfaces),
+ * fallback to using a 'topology' cost.
+ *
+ * This avoids cases where a flat (or near flat) areas get very un-even geometry.
+ */
+static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
+{
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+}
+static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
+{
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+}
+
+#endif /* USE_TOPOLOGY_FALLBACK */
+
+static void bm_decim_build_edge_cost_single(
+ BMEdge *e,
+ const Quadric *vquadrics,
+ const float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table)
{
const Quadric *q1, *q2;
float optimize_co[3];
@@ -202,8 +244,7 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
}
else {
/* only collapse tri's */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
+ goto clear;
}
}
else if (BM_edge_is_manifold(e)) {
@@ -212,23 +253,11 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
}
else {
/* only collapse tri's */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
+ goto clear;
}
}
else {
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
- }
-
- if (vweights) {
- if ((vweights[BM_elem_index_get(e->v1)] >= BM_MESH_DECIM_WEIGHT_MAX) &&
- (vweights[BM_elem_index_get(e->v2)] >= BM_MESH_DECIM_WEIGHT_MAX))
- {
- /* skip collapsing this edge */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
- }
+ goto clear;
}
/* end sanity check */
@@ -238,36 +267,71 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
q1 = &vquadrics[BM_elem_index_get(e->v1)];
q2 = &vquadrics[BM_elem_index_get(e->v2)];
- if (vweights == NULL) {
- cost = (BLI_quadric_evaluate(q1, optimize_co) +
- BLI_quadric_evaluate(q2, optimize_co));
- }
- else {
- /* add 1.0 so planar edges are still weighted against */
- cost = (((BLI_quadric_evaluate(q1, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v1)]) +
- ((BLI_quadric_evaluate(q2, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v2)]));
- }
- // print("COST %.12f\n");
+ cost = (BLI_quadric_evaluate(q1, optimize_co) +
+ BLI_quadric_evaluate(q2, optimize_co));
+
/* note, 'cost' shouldn't be negative but happens sometimes with small values.
* this can cause faces that make up a flat surface to over-collapse, see [#37121] */
cost = fabsf(cost);
+
+#ifdef USE_TOPOLOGY_FALLBACK
+ if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
+ /* subtract existing cost to further differentiate edges from one another
+ *
+ * keep topology cost below 0.0 so their values don't interfere with quadric cost,
+ * (and they get handled first).
+ * */
+ if (vweights == NULL) {
+ cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
+ }
+ else {
+ /* with weights we need to use the real length so we can scale them properly */
+ const float e_weight = (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ cost = bm_decim_build_edge_cost_single__topology(e) - cost;
+ /* note, this is rather arbitrary max weight is 2 here,
+ * allow for skipping edges 4x the length, based on weights */
+ if (e_weight) {
+ cost *= 1.0f + (e_weight * vweight_factor);
+ }
+
+ BLI_assert(cost <= 0.0f);
+ }
+ }
+ else
+#endif
+ if (vweights) {
+ const float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ if (e_weight) {
+ cost += (BM_edge_calc_length(e) * ((e_weight * vweight_factor)));
+ }
+ }
+
eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e);
+ return;
+
+clear:
+ eheap_table[BM_elem_index_get(e)] = NULL;
}
/* use this for degenerate cases - add back to the heap with an invalid cost,
* this way it may be calculated again if surrounding geometry changes */
-static void bm_decim_invalid_edge_cost_single(BMEdge *e,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_invalid_edge_cost_single(
+ BMEdge *e,
+ Heap *eheap, HeapNode **eheap_table)
{
BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL);
eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
}
-static void bm_decim_build_edge_cost(BMesh *bm,
- const Quadric *vquadrics, const float *vweights,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_build_edge_cost(
+ BMesh *bm,
+ const Quadric *vquadrics,
+ const float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table)
{
BMIter iter;
BMEdge *e;
@@ -275,7 +339,7 @@ static void bm_decim_build_edge_cost(BMesh *bm,
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
eheap_table[i] = NULL; /* keep sanity check happy */
- bm_decim_build_edge_cost_single(e, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e, vquadrics, vweights, vweight_factor, eheap, eheap_table);
}
}
@@ -440,10 +504,11 @@ static void bm_decim_triangulate_end(BMesh *bm)
#ifdef USE_CUSTOMDATA
/**
- * \param v is the target to merge into.
+ * \param l: defines the vert to collapse into.
*/
-static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
- const float customdata_fac)
+static void bm_edge_collapse_loop_customdata(
+ BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
+ const float customdata_fac)
{
/* disable seam check - the seam check would have to be done per layer, its not really that important */
//#define USE_SEAM
@@ -452,8 +517,6 @@ static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_cle
const bool is_manifold = BM_edge_is_manifold(l->e);
int side;
- /* l defines the vert to collapse into */
-
/* first find the loop of 'v_other' thats attached to the face of 'l' */
if (l->v == v_clear) {
l_clear = l;
@@ -695,18 +758,19 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
*
* Important - dont add vert/edge/face data on collapsing!
*
- * \param e_clear_other let caller know what edges we remove besides \a e_clear
- * \param customdata_flag merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
+ * \param r_e_clear_other: Let caller know what edges we remove besides \a e_clear
+ * \param customdata_flag: Merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
*/
-static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
+static bool bm_edge_collapse(
+ BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
#ifdef USE_CUSTOMDATA
- const CD_UseFlag customdata_flag,
- const float customdata_fac
+ const CD_UseFlag customdata_flag,
+ const float customdata_fac
#else
- const CD_UseFlag UNUSED(customdata_flag),
- const float UNUSED(customdata_fac)
+ const CD_UseFlag UNUSED(customdata_flag),
+ const float UNUSED(customdata_fac)
#endif
- )
+ )
{
BMVert *v_other;
@@ -782,12 +846,12 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
BM_edge_kill(bm, e_clear);
v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_clear, v_other);
+ BM_vert_splice(bm, v_other, v_clear);
e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
- BM_edge_splice(bm, e_b_other[0], e_b_other[1]);
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
+ BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
// BM_mesh_validate(bm);
@@ -831,10 +895,10 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
BM_edge_kill(bm, e_clear);
v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_clear, v_other);
+ BM_vert_splice(bm, v_other, v_clear);
e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
// BM_mesh_validate(bm);
@@ -847,14 +911,17 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
/* collapse e the edge, removing e->v2 */
-static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
- Quadric *vquadrics, float *vweights,
- Heap *eheap, HeapNode **eheap_table,
- const CD_UseFlag customdata_flag)
+static void bm_decim_edge_collapse(
+ BMesh *bm, BMEdge *e,
+ Quadric *vquadrics,
+ float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table,
+ const CD_UseFlag customdata_flag)
{
int e_clear_other[2];
BMVert *v_other = e->v1;
- int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
+ const int v_other_index = BM_elem_index_get(e->v1);
+ const int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
float optimize_co[3];
float customdata_fac;
@@ -897,7 +964,9 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
int i;
if (vweights) {
- vweights[BM_elem_index_get(v_other)] += vweights[v_clear_index];
+ float v_other_weight = interpf(vweights[v_other_index], vweights[v_clear_index], customdata_fac);
+ CLAMP(v_other_weight, 0.0f, 1.0f);
+ vweights[v_other_index] = v_other_weight;
}
e = NULL; /* paranoid safety check */
@@ -914,7 +983,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
}
/* update vertex quadric, add kept vertex from killed vertex */
- BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(v_other)], &vquadrics[v_clear_index]);
+ BLI_quadric_add_qu_qu(&vquadrics[v_other_index], &vquadrics[v_clear_index]);
/* update connected normals */
@@ -935,7 +1004,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
e_iter = e_first = v_other->e;
do {
BLI_assert(BM_edge_find_double(e_iter) == NULL);
- bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
} while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
}
@@ -957,7 +1026,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
- bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
}
}
}
@@ -981,7 +1050,11 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
*/
-void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, const bool do_triangulate)
+void BM_mesh_decimate_collapse(
+ BMesh *bm,
+ const float factor,
+ float *vweights, float vweight_factor,
+ const bool do_triangulate)
{
Heap *eheap; /* edge heap */
HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
@@ -1009,7 +1082,7 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
/* build initial edge collapse cost data */
bm_decim_build_quadrics(bm, vquadrics);
- bm_decim_build_edge_cost(bm, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost(bm, vquadrics, vweights, vweight_factor, eheap, eheap_table);
face_tot_target = bm->totface * factor;
bm->elem_index_dirty |= BM_ALL;
@@ -1031,13 +1104,11 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
BMEdge *e = BLI_heap_popmin(eheap);
BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */
- // printf("COST %.10f\n", value);
-
/* under normal conditions wont be accessed again,
* but NULL just incase so we don't use freed node */
eheap_table[BM_elem_index_get(e)] = NULL;
- bm_decim_edge_collapse(bm, e, vquadrics, vweights, eheap, eheap_table, customdata_flag);
+ bm_decim_edge_collapse(bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table, customdata_flag);
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 096349e8e9c..a1460cec7d1 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -32,6 +32,8 @@
#include "BLI_math.h"
#include "BLI_heap.h"
+#include "BKE_customdata.h"
+
#include "bmesh.h"
#include "bmesh_decimate.h" /* own include */
@@ -59,7 +61,32 @@ static float bm_vert_edge_face_angle(BMVert *v)
#undef ANGLE_TO_UNIT
}
-static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit delimit)
+struct DelimitData {
+ int cd_loop_type;
+ int cd_loop_size;
+ int cd_loop_offset;
+ int cd_loop_offset_end;
+};
+
+static bool bm_edge_is_contiguous_loop_cd_all(
+ const BMEdge *e, const struct DelimitData *delimit_data)
+{
+ int cd_loop_offset;
+ for (cd_loop_offset = delimit_data->cd_loop_offset;
+ cd_loop_offset < delimit_data->cd_loop_offset_end;
+ cd_loop_offset += delimit_data->cd_loop_size)
+ {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static float bm_edge_calc_dissolve_error(
+ const BMEdge *e, const BMO_Delimit delimit,
+ const struct DelimitData *delimit_data)
{
const bool is_contig = BM_edge_is_contiguous(e);
float angle;
@@ -74,6 +101,12 @@ static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit deli
goto fail;
}
+ if ((delimit & BMO_DELIM_SHARP) &&
+ (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0))
+ {
+ goto fail;
+ }
+
if ((delimit & BMO_DELIM_MATERIAL) &&
(e->l->f->mat_nr != e->l->radial_next->f->mat_nr))
{
@@ -86,6 +119,12 @@ static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit deli
goto fail;
}
+ if ((delimit & BMO_DELIM_UV) &&
+ (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0))
+ {
+ goto fail;
+ }
+
angle = BM_edge_calc_face_angle(e);
if (is_contig == false) {
angle = (float)M_PI - angle;
@@ -98,17 +137,32 @@ fail:
}
-void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out)
+void BM_mesh_decimate_dissolve_ex(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr, const int vinput_len,
+ BMEdge **einput_arr, const int einput_len,
+ const short oflag_out)
{
+ struct DelimitData delimit_data = {0};
const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
int i;
+ if (delimit & BMO_DELIM_UV) {
+ const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ if (layer_len == 0) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ else {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
+ delimit_data.cd_loop_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, 0);
+ delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
+ }
+ }
+
/* --- first edges --- */
if (1) {
BMEdge **earray;
@@ -133,7 +187,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
/* build heap */
for (i = 0; i < einput_len; i++) {
BMEdge *e = einput_arr[i];
- const float cost = bm_edge_calc_dissolve_error(e, delimit);
+ const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
eheap_table[i] = BLI_heap_insert(eheap, cost, e);
BM_elem_index_set(e, i); /* set dirty */
}
@@ -169,7 +223,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
do {
const int j = BM_elem_index_get(l_iter->e);
if (j != -1 && eheap_table[j]) {
- const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit);
+ const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
BLI_heap_remove(eheap, eheap_table[j]);
eheap_table[j] = BLI_heap_insert(eheap, cost, l_iter->e);
}
@@ -189,7 +243,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
/* prepare for cleanup */
BM_mesh_elem_index_ensure(bm, BM_VERT);
vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
- fill_vn_i(vert_reverse_lookup, bm->totvert, -1);
+ copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
for (i = 0; i < vinput_len; i++) {
BMVert *v = vinput_arr[i];
vert_reverse_lookup[BM_elem_index_get(v)] = i;
@@ -316,8 +370,9 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
MEM_freeN(_heap_table);
}
-void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit)
+void BM_mesh_decimate_dissolve(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit)
{
int vinput_len;
int einput_len;
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 1328b81b746..2a1946df7ae 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -166,8 +166,8 @@ static BMFace *bm_edgenet_face_from_path(
{
BMFace *f;
LinkNode *v_lnk;
- unsigned int i;
- unsigned int i_prev;
+ int i;
+ bool ok;
BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
BMEdge **edge_arr = BLI_array_alloca(edge_arr, path_len);
@@ -176,11 +176,9 @@ static BMFace *bm_edgenet_face_from_path(
vert_arr[i] = v_lnk->link;
}
- i_prev = path_len - 1;
- for (i = 0; i < path_len; i++) {
- edge_arr[i_prev] = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
- i_prev = i;
- }
+ ok = BM_edges_from_verts(edge_arr, vert_arr, i);
+ BLI_assert(ok);
+ UNUSED_VARS_NDEBUG(ok);
/* no need for this, we do overlap checks before allowing the path to be used */
#if 0
@@ -448,10 +446,10 @@ static LinkNode *bm_edgenet_path_calc_best(
*
* \param bm The mesh to operate on.
* \param use_edge_tag Only fill tagged edges.
- * \param face_oflag if nonzero, apply all new faces with this bmo flag.
*/
-void BM_mesh_edgenet(BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag)
+void BM_mesh_edgenet(
+ BMesh *bm,
+ const bool use_edge_tag, const bool use_new_face_tag)
{
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
BLI_mempool *edge_queue_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 327a7f5aa23..1ad5cadae7c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -27,7 +27,8 @@
* \ingroup bmesh
*/
-void BM_mesh_edgenet(BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag);
+void BM_mesh_edgenet(
+ BMesh *bm,
+ const bool use_edge_tag, const bool use_new_face_tag);
#endif /* __BMESH_EDGENET_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 947b77675d8..a59a5c43c82 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -35,70 +35,15 @@
#include "bmesh_edgesplit.h" /* own include */
-
/**
- * Remove the BM_ELEM_TAG flag for edges we cant split
- *
- * un-tag edges not connected to other tagged edges,
- * unless they are on a boundary
+ * \param use_verts Use flagged verts instead of edges.
+ * \param tag_only Only split tagged edges.
+ * \param copy_select Copy selection history.
*/
-static void bm_edgesplit_validate_seams(BMesh *bm)
-{
- BMIter iter;
- BMEdge *e;
-
- unsigned char *vtouch;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- vtouch = MEM_callocN(sizeof(char) * bm->totvert, __func__);
-
- /* tag all boundary verts so as not to untag an edge which is inbetween only 2 faces [] */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
-
- /* unrelated to flag assignment in this function - since this is the
- * only place we loop over all edges, disable tag */
- BM_elem_flag_disable(e, BM_ELEM_INTERNAL_TAG);
-
- if (e->l == NULL) {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- else if (BM_edge_is_boundary(e)) {
- unsigned char *vt;
- vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
- vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
-
- /* while the boundary verts need to be tagged,
- * the edge its self can't be split */
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- }
-
- /* single marked edges unconnected to any other marked edges
- * are illegal, go through and unmark them */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* lame, but we don't want the count to exceed 255,
- * so just count to 2, its all we need */
- unsigned char *vt;
- vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
- vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
- }
- }
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- if (vtouch[BM_elem_index_get(e->v1)] == 1 &&
- vtouch[BM_elem_index_get(e->v2)] == 1)
- {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- }
- }
-
- MEM_freeN(vtouch);
-}
-
-void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select)
+void BM_mesh_edgesplit(
+ BMesh *bm,
+ const bool use_verts,
+ const bool tag_only, const bool copy_select)
{
BMIter iter;
BMEdge *e;
@@ -142,43 +87,13 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
}
}
- bm_edgesplit_validate_seams(bm);
-
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* this flag gets copied so we can be sure duplicate edges get it too (important) */
- BM_elem_flag_enable(e, BM_ELEM_INTERNAL_TAG);
-
- /* keep splitting until each loop has its own edge */
- while (!BM_edge_is_boundary(e)) {
- BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
- BLI_assert(l_sep->e != e);
-
- if (use_ese) {
- BMEditSelection *ese = BLI_ghash_lookup(ese_gh, e);
- if (UNLIKELY(ese)) {
- BM_select_history_store_after_notest(bm, ese, l_sep->e);
- }
- }
- }
-
BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
- if (use_verts) {
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) == false) {
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- }
- if (BM_elem_flag_test(e->v2, BM_ELEM_TAG) == false) {
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
- }
- }
- }
-
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
unsigned int i;
@@ -191,7 +106,7 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
BMVert **vtar;
int vtar_len;
- bmesh_vert_separate(bm, v, &vtar, &vtar_len, copy_select);
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, &vtar, &vtar_len);
/* first value is always in 'v' */
if (vtar_len > 1) {
@@ -208,13 +123,22 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
MEM_freeN(vtar);
}
else {
- bmesh_vert_separate(bm, v, NULL, NULL, copy_select);
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, NULL, NULL);
}
}
}
}
}
+#ifndef NDEBUG
+ /* ensure we don't have any double edges! */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BLI_assert(BM_edge_find_double(e) == NULL);
+ }
+ }
+#endif
+
if (use_ese) {
BLI_ghash_free(ese_gh, NULL, NULL);
}
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index bd66f6a9e2f..26040077f43 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -27,6 +27,9 @@
* \ingroup bmesh
*/
-void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select);
+void BM_mesh_edgesplit(
+ BMesh *bm,
+ const bool use_verts,
+ const bool tag_only, const bool copy_select);
#endif /* __BMESH_EDGESPLIT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 064dbd7405b..fc12bce8563 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -804,7 +804,7 @@ bool BM_mesh_intersect(
s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
s.edge_verts = BLI_ghash_ptr_new(__func__);
- s.face_edges = BLI_ghash_ptr_new(__func__);
+ s.face_edges = BLI_ghash_int_new(__func__);
s.wire_edges = BLI_gset_ptr_new(__func__);
s.vert_dissolve = NULL;
@@ -1006,7 +1006,7 @@ bool BM_mesh_intersect(
!BM_vert_splice_check_double(v_prev, vi) &&
!BM_vert_pair_share_face_check(v_prev, vi))
{
- BM_vert_splice(bm, v_prev, vi);
+ BM_vert_splice(bm, vi, v_prev);
}
else {
copy_v3_v3(v_prev->co, vi->co);
@@ -1040,8 +1040,8 @@ bool BM_mesh_intersect(
}
}
- splice_ls = MEM_mallocN((unsigned int)BLI_gset_size(s.wire_edges) * sizeof(*splice_ls), __func__);
- STACK_INIT(splice_ls, (unsigned int)BLI_gset_size(s.wire_edges));
+ splice_ls = MEM_mallocN(BLI_gset_size(s.wire_edges) * sizeof(*splice_ls), __func__);
+ STACK_INIT(splice_ls, BLI_gset_size(s.wire_edges));
for (node = s.vert_dissolve; node; node = node->next) {
BMEdge *e_pair[2];
@@ -1228,7 +1228,7 @@ bool BM_mesh_intersect(
if (!BM_edge_exists(UNPACK2(splice_ls[i])) &&
!BM_vert_splice_check_double(UNPACK2(splice_ls[i])))
{
- BM_vert_splice(bm, UNPACK2(splice_ls[i]));
+ BM_vert_splice(bm, splice_ls[i][1], splice_ls[i][0]);
}
}
}
@@ -1267,10 +1267,8 @@ bool BM_mesh_intersect(
face_edges_split(bm, f, e_ls_base);
}
}
-#else
- (void)totface_orig;
#endif /* USE_NET */
-
+ (void)totface_orig;
#ifdef USE_SEPARATE
if (use_separate) {
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 8ae3507a738..6633803414b 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -126,7 +126,7 @@ LinkNode *BM_mesh_calc_path_vert(
verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
- fill_vn_fl(cost, totvert, 1e20f);
+ copy_vn_fl(cost, totvert, 1e20f);
/*
* Arrays are now filled as follows:
@@ -252,7 +252,7 @@ LinkNode *BM_mesh_calc_path_edge(
edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
- fill_vn_fl(cost, totedge, 1e20f);
+ copy_vn_fl(cost, totedge, 1e20f);
/*
* Arrays are now filled as follows:
@@ -378,7 +378,7 @@ LinkNode *BM_mesh_calc_path_face(
faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
- fill_vn_fl(cost, totface, 1e20f);
+ copy_vn_fl(cost, totface, 1e20f);
/*
* Arrays are now filled as follows:
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 43fd1368bb7..a6860a6614a 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -190,14 +190,18 @@ static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
return (a != b);
}
-static GHash *ghash_bmelem_new_ex(const char *info, const unsigned int nentries_reserve)
+static GHash *ghash_bmelem_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve, false);
+ 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)
+static GSet *gset_bmelem_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve)
{
- return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve, false);
+ return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
@@ -417,8 +421,8 @@ static void bm_uuidwalk_rehash(
UUID_Int *uuid_store;
unsigned int i;
- unsigned int rehash_store_len_new = (unsigned int)MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
- BLI_ghash_size(uuidwalk->faces_uuid));
+ unsigned int 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);
uuid_store = uuidwalk->cache.rehash_store;
@@ -507,7 +511,7 @@ static void bm_uuidwalk_pass_add(
UUIDFaceStep *fstep;
- BLI_assert(faces_pass_len == (unsigned int)BLI_linklist_length(faces_pass));
+ BLI_assert(faces_pass_len == (unsigned int)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);
@@ -532,12 +536,13 @@ static void bm_uuidwalk_pass_add(
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
/* fill verts_new */
+ void **val_p;
if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
- !BLI_ghash_haskey(verts_uuid_pass, l_iter->v) &&
+ !BLI_ghash_ensure_p(verts_uuid_pass, l_iter->v, &val_p) &&
(bm_vert_is_uuid_connect(uuidwalk, l_iter->v) == true))
{
const UUID_Int uuid = bm_uuidwalk_calc_vert_uuid(uuidwalk, l_iter->v);
- BLI_ghash_insert(verts_uuid_pass, l_iter->v, (void *)uuid);
+ *val_p = (void *)uuid;
}
/* fill faces_step_next */
@@ -612,15 +617,16 @@ static unsigned int bm_uuidwalk_init_from_edge(
/* turning an array into LinkNode's seems odd,
* but this is just for initialization,
* elsewhere using LinkNode's makes more sense */
- for (i = 0; i < f_arr_len; i++) {
+ for (i = 0; i < f_arr_len; ) {
LinkNode *faces_pass = NULL;
+ const unsigned int i_init = i;
const int f_len = f_arr[i]->len;
do {
BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uuidwalk->link_pool);
} while (i < f_arr_len && (f_len == f_arr[i]->len));
- bm_uuidwalk_pass_add(uuidwalk, faces_pass, i);
+ bm_uuidwalk_pass_add(uuidwalk, faces_pass, i - i_init);
BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
fstep_num += 1;
}
@@ -665,13 +671,15 @@ static bool bm_uuidwalk_facestep_begin(
if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
UUIDFaceStepItem *fstep_item;
+ void **val_p;
ok = true;
- fstep_item = BLI_ghash_lookup(uuidwalk->cache.faces_from_uuid, (void *)uuid);
- if (UNLIKELY(fstep_item == NULL)) {
- fstep_item = BLI_mempool_alloc(uuidwalk->step_pool_items);
- BLI_ghash_insert(uuidwalk->cache.faces_from_uuid, (void *)uuid, fstep_item);
+ if (BLI_ghash_ensure_p(uuidwalk->cache.faces_from_uuid, (void *)uuid, &val_p)) {
+ fstep_item = *val_p;
+ }
+ else {
+ fstep_item = *val_p = BLI_mempool_alloc(uuidwalk->step_pool_items);
/* add to start, so its handled on the next round of passes */
BLI_addhead(&fstep->items, fstep_item);
@@ -856,7 +864,7 @@ static BMFace **bm_mesh_region_match_pair(
break;
}
- found = ((unsigned int)BLI_ghash_size(w_dst->faces_uuid) == faces_src_region_len);
+ found = (BLI_ghash_size(w_dst->faces_uuid) == faces_src_region_len);
if (found) {
break;
}
@@ -869,7 +877,7 @@ static BMFace **bm_mesh_region_match_pair(
if (found) {
GHashIterator gh_iter;
- const unsigned int faces_result_len = (unsigned int)BLI_ghash_size(w_dst->faces_uuid);
+ const unsigned int faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
unsigned int i;
faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
@@ -1109,9 +1117,10 @@ static BMEdge *bm_face_region_pivot_edge_find(
if (bm_edge_is_region_boundary(e)) {
unsigned int j;
for (j = 0; j < 2; j++) {
- if (!BLI_ghash_haskey(gh, (&e->v1)[j])) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
- BLI_ghash_insert(gh, (&e->v1)[j], (void *)v_id);
+ *val_p = (void *)v_id;
BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
vert_queue_used += 1;
}
@@ -1135,10 +1144,11 @@ static BMEdge *bm_face_region_pivot_edge_find(
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
- if (!BLI_ghash_haskey(gh, v_other)) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
/* add as negative, so we know not to read from them this pass */
const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
- BLI_ghash_insert(gh, v_other, (void *)v_id_other);
+ *val_p = (void *)v_id_other;
BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
vert_queue_used += 1;
}
@@ -1449,7 +1459,7 @@ int BM_mesh_region_match(
BMFace **faces_result;
unsigned int faces_result_len_out;
- if (BM_elem_flag_test(e_dst, BM_ELEM_TAG)) {
+ 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_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c
index 404776a0769..6f2aaf28179 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.c
+++ b/source/blender/bmesh/tools/bmesh_triangulate.c
@@ -34,7 +34,6 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_memarena.h"
-#include "BLI_listbase.h"
#include "BLI_heap.h"
#include "BLI_edgehash.h"
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index 550109ffef9..c6a5e04dfb2 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -30,7 +30,8 @@
#ifndef __BMESH_TRIANGULATE_H__
#define __BMESH_TRIANGULATE_H__
-void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
- BMOperator *op, BMOpSlot *slot_facemap_out);
+void BM_mesh_triangulate(
+ BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
+ BMOperator *op, BMOpSlot *slot_facemap_out);
#endif /* __BMESH_TRIANGULATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index 79fea3e5da1..e79ef52797b 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -55,8 +55,9 @@ static BMLoop *bm_edge_tag_faceloop(BMEdge *e)
return NULL;
}
-static void bm_vert_boundary_tangent(BMVert *v, float r_no[3], float r_no_face[3],
- BMVert **r_va_other, BMVert **r_vb_other)
+static void bm_vert_boundary_tangent(
+ BMVert *v, float r_no[3], float r_no_face[3],
+ BMVert **r_va_other, BMVert **r_vb_other)
{
BMIter iter;
BMEdge *e_iter;
@@ -159,7 +160,7 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
}
/**
- * \param def_nr -1 for no vertex groups.
+ * \param defgrp_index: Vertex group index, -1 for no vertex groups.
*
* \note All edge tags must be cleared.
* \note Behavior matches MOD_solidify.c
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index de4e29a7d48..7bea0b70c95 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -185,7 +185,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {NULL, NULL};
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!validateConstraints(con)) continue;
@@ -1526,7 +1526,7 @@ void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, i
bool AnimationExporter::validateConstraints(bConstraint *con)
{
bool valid = true;
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* these we can skip completely (invalid constraints...) */
if (cti == NULL) valid = false;
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
@@ -1545,7 +1545,7 @@ void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {NULL, NULL};
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index 6f675ed6a39..4736361ad13 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -103,7 +103,7 @@ protected:
const ExportSettings *export_settings;
void dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
-
+
void export_object_constraint_animation(Object *ob);
void export_morph_animation(Object *ob);
@@ -154,7 +154,7 @@ protected:
std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id);
-
+
std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index c2ee6170470..bccaf4eddf6 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -588,9 +588,11 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
/* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
+ if (armature->bonebase.first) {
+ /* Do this only if Armature has bones */
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+ }
// exit armature edit mode
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 16c3f68bca4..06e151c363b 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -284,7 +284,8 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
}
if (oob_counter > 0) {
- fprintf(stderr, "Ignored %d Vertex weights which use index to non existing VGroup %ld.\n", oob_counter, joint_index_by_def_index.size());
+ fprintf(stderr, "Ignored %d Vertex weights which use index to non existing VGroup %lu.\n",
+ oob_counter, joint_index_by_def_index.size());
}
}
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 462b7b6f200..0aff5147060 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -771,9 +771,9 @@ MTex *DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::T
return NULL;
}
- ma->mtex[i] = add_mtex();
+ ma->mtex[i] = BKE_texture_mtex_add();
ma->mtex[i]->texco = TEXCO_UV;
- ma->mtex[i]->tex = add_texture(G.main, "Texture");
+ ma->mtex[i]->tex = BKE_texture_add(G.main, "Texture");
ma->mtex[i]->tex->type = TEX_IMAGE;
ma->mtex[i]->tex->ima = uid_image_map[ima_uid];
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 5a7df9a41cf..62f76dbc022 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -51,7 +51,6 @@
-struct Main;
struct bContext;
/** Importer class. */
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 28cee05ec4b..7c7c57f3305 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -532,8 +532,8 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
// each <source> will get id like meshName + "map-channel-1"
int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
for (int a = 0; a < num_layers; a++) {
-
- if (!this->export_settings->active_uv_only || a == active_uv_index) {
+ int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
+ if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
@@ -563,6 +563,11 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
}
}
+bool operator<(const Normal &a, const Normal &b)
+{
+ /* only needed to sort normal vectors and find() them later in a map.*/
+ return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
+}
//creates <source> for normals
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
@@ -596,15 +601,25 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v
void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
{
- std::map<unsigned int, unsigned int> shared_normal_indices;
+ std::map<Normal, unsigned int> shared_normal_indices;
int last_normal_index = -1;
MVert *verts = me->mvert;
MLoop *mloops = me->mloop;
+ float(*lnors)[3] = NULL;
+ bool use_custom_normals = false;
+
+ BKE_mesh_calc_normals_split(me);
+ if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
+ lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
+ use_custom_normals = true;
+ }
+
for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
MPoly *mpoly = &me->mpoly[poly_index];
+ bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
- if (!(mpoly->flag & ME_SMOOTH)) {
+ if (!use_vertex_normals) {
// For flat faces use face normal as vertex normal:
float vector[3];
@@ -615,25 +630,29 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<
last_normal_index++;
}
-
- MLoop *mloop = mloops + mpoly->loopstart;
BCPolygonNormalsIndices poly_indices;
for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
- unsigned int vertex_index = mloop[loop_index].v;
- if (mpoly->flag & ME_SMOOTH) {
- if (shared_normal_indices.find(vertex_index) != shared_normal_indices.end())
- poly_indices.add_index (shared_normal_indices[vertex_index]);
- else {
+ unsigned int loop_idx = mpoly->loopstart + loop_index;
+ if (use_vertex_normals) {
+ float normalized[3];
- float vector[3];
- normal_short_to_float_v3(vector, verts[vertex_index].no);
+ if (use_custom_normals) {
+ normalize_v3_v3(normalized, lnors[loop_idx]);
+ }
+ else {
+ normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
+ normalize_v3(normalized);
+ }
+ Normal n = { normalized[0], normalized[1], normalized[2] };
- Normal n = { vector[0], vector[1], vector[2] };
- normals.push_back(n);
+ if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
+ poly_indices.add_index(shared_normal_indices[n]);
+ }
+ else {
last_normal_index++;
-
poly_indices.add_index(last_normal_index);
- shared_normal_indices[vertex_index] = last_normal_index;
+ shared_normal_indices[n] = last_normal_index;
+ normals.push_back(n);
}
}
else {
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 4d54e79d796..69d1067e6f4 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -48,6 +48,20 @@
extern Object *bc_get_highest_selected_ancestor_or_self(Object *ob);
+class Normal
+{
+ public:
+ float x;
+ float y;
+ float z;
+
+ friend bool operator< (const Normal &, const Normal &);
+
+};
+
+bool operator< (const Normal &, const Normal &);
+
+
// TODO: optimize UV sets by making indexed list with duplicates removed
class GeometryExporter : COLLADASW::LibraryGeometries
{
@@ -56,10 +70,7 @@ class GeometryExporter : COLLADASW::LibraryGeometries
unsigned int v1, v2, v3, v4;
};
- struct Normal
- {
- float x, y, z;
- };
+ Normal n;
Scene *mScene;
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index a5c1493208b..aac41e2e93c 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -74,7 +74,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
- bool is_packed = image->packedfile != NULL;
+ bool is_packed = BKE_image_has_packedfile(image);
char export_path[FILE_MAX];
char source_path[FILE_MAX];
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index b50b8b0a302..ac8ac2b9867 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -150,7 +150,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
if (!instance_controller_created) {
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);
instGeom.add();
@@ -210,7 +210,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
//not ideal: add the target object name as another parameter.
//No real mapping in the .dae
//Need support for multiple target objects also.
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index f1d5f1a208a..4ca21869ec2 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -116,7 +116,7 @@ int collada_export(Scene *sce,
eObjectSet objectSet = (export_settings.selected) ? OB_SET_SELECTED : OB_SET_ALL;
export_settings.export_set = BKE_object_relational_superset(sce, objectSet, (eObRelationTypes)includeFilter);
- int export_count = BLI_linklist_length(export_settings.export_set);
+ int export_count = BLI_linklist_count(export_settings.export_set);
if (export_count==0)
{
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f15efa89ea6..d669487db28 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -131,7 +131,7 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
{
Object *ob = BKE_object_add_only_object(G.main, type, name);
- ob->data = BKE_object_obdata_add_from_type(G.main, type);
+ ob->data = BKE_object_obdata_add_from_type(G.main, type, name);
ob->lay = scene->lay;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
@@ -144,6 +144,7 @@ Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh
{
Mesh *tmpmesh;
CustomDataMask mask = CD_MASK_MESH;
+ Mesh *mesh = (Mesh *)ob->data;
DerivedMesh *dm = NULL;
if (apply_modifiers) {
switch (export_mesh_type) {
@@ -165,14 +166,12 @@ Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh
tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true);
+ tmpmesh->flag = mesh->flag;
if (triangulate) {
bc_triangulate_mesh(tmpmesh);
}
-
- // XXX Not sure if we need that for ngon_export as well.
BKE_mesh_tessface_ensure(tmpmesh);
-
return tmpmesh;
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 048c974423f..0d35d060f5f 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -41,6 +41,7 @@ set(INC
../render/intern/include
../../../extern/clew/include
../../../intern/guardedalloc
+ ../../../intern/atomic
)
set(INC_SYS
@@ -119,6 +120,8 @@ set(SRC
nodes/COM_TimeNode.h
nodes/COM_SwitchNode.cpp
nodes/COM_SwitchNode.h
+ nodes/COM_SwitchViewNode.cpp
+ nodes/COM_SwitchViewNode.h
nodes/COM_MovieClipNode.cpp
nodes/COM_MovieClipNode.h
nodes/COM_OutputFileNode.cpp
@@ -370,6 +373,8 @@ set(SRC
operations/COM_CompositorOperation.cpp
operations/COM_OutputFileOperation.h
operations/COM_OutputFileOperation.cpp
+ operations/COM_OutputFileMultiViewOperation.h
+ operations/COM_OutputFileMultiViewOperation.cpp
operations/COM_ViewerOperation.h
operations/COM_ViewerOperation.cpp
operations/COM_PreviewOperation.h
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 9b22444cf7f..a5d7704a708 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -38,7 +38,7 @@ extern "C" {
* @defgroup Node All nodes of the compositor
* @defgroup Operation All operations of the compositor
*
- * @mainpage Introduction of the Blender Compositor
+ * @page Introduction of the Blender Compositor
*
* @section bcomp Blender compositor
* This project redesigns the internals of Blender's compositor. The project has been executed in 2011 by At Mind.
@@ -316,7 +316,8 @@ extern "C" {
* generation in display space
*/
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
/**
* @brief Deinitialize the compositor caches and allocated memory.
diff --git a/source/blender/compositor/SConscript b/source/blender/compositor/SConscript
index eab40873f64..370600a594e 100644
--- a/source/blender/compositor/SConscript
+++ b/source/blender/compositor/SConscript
@@ -50,6 +50,7 @@ incs = [
'../render/intern/include',
'../windowmanager',
'../../../intern/guardedalloc',
+ '../../../intern/atomic',
# data files
env['DATA_HEADERS'],
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index 3fbafa0a029..d7ec653f480 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -87,6 +87,11 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
+ /**
+ * @brief active rendering view name
+ */
+ const char *m_viewName;
+
public:
/**
* @brief constructor initializes the context with default values.
@@ -180,7 +185,17 @@ public:
* @brief set has this system active openclDevices?
*/
void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices) { this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices; }
-
+
+ /**
+ * @brief get the active rendering view
+ */
+ const char *getViewName() const { return this->m_viewName; }
+
+ /**
+ * @brief set the active rendering view
+ */
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
+
int getChunksize() const { return this->getbNodeTree()->chunksize; }
void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;}
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 99f66bcb5b4..9fa59be4a1c 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -101,6 +101,7 @@ extern "C" {
#include "COM_Stabilize2dNode.h"
#include "COM_SunBeamsNode.h"
#include "COM_SwitchNode.h"
+#include "COM_SwitchViewNode.h"
#include "COM_TextureNode.h"
#include "COM_TimeNode.h"
#include "COM_TonemapNode.h"
@@ -136,6 +137,10 @@ Node *Converter::convert(bNode *b_node)
{
Node *node = NULL;
+ /* ignore undefined nodes with missing or invalid node data */
+ if (!nodeIsRegistered(b_node))
+ return NULL;
+
switch (b_node->type) {
case CMP_NODE_COMPOSITE:
node = new CompositorNode(b_node);
@@ -328,6 +333,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_SWITCH:
node = new SwitchNode(b_node);
break;
+ case CMP_NODE_SWITCH_VIEW:
+ node = new SwitchViewNode(b_node);
+ break;
case CMP_NODE_GLARE:
node = new GlareNode(b_node);
break;
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index ffaa4cc45a8..a7b464cde29 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -213,7 +213,7 @@ int DebugInfo::graphviz_legend_color(const char *name, const char *color, char *
return len;
}
-int DebugInfo::graphviz_legend_line(const char *name, const char *color, const char *style, char *str, int maxlen)
+int DebugInfo::graphviz_legend_line(const char * /*name*/, const char * /*color*/, const char * /*style*/, char *str, int maxlen)
{
/* XXX TODO */
int len = 0;
@@ -221,7 +221,7 @@ int DebugInfo::graphviz_legend_line(const char *name, const char *color, const c
return len;
}
-int DebugInfo::graphviz_legend_group(const char *name, const char *color, const char *style, char *str, int maxlen)
+int DebugInfo::graphviz_legend_group(const char *name, const char *color, const char * /*style*/, char *str, int maxlen)
{
int len = 0;
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD>%s</TD><TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\"><TR><TD BGCOLOR=\"%s\"></TD></TR></TABLE></TD></TR>\r\n", name, color);
@@ -356,7 +356,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
std::string color;
switch (from->getDataType()) {
case COM_DT_VALUE:
- color = "grey";
+ color = "gray";
break;
case COM_DT_VECTOR:
color = "blue";
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index 366c97b50c6..5cb757d7dcb 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -25,12 +25,13 @@
#include <sstream>
#include <stdlib.h>
+#include "atomic_ops.h"
+
#include "COM_ExecutionGroup.h"
#include "COM_defines.h"
#include "COM_ExecutionSystem.h"
#include "COM_ReadBufferOperation.h"
#include "COM_WriteBufferOperation.h"
-#include "COM_ReadBufferOperation.h"
#include "COM_WorkScheduler.h"
#include "COM_ViewerOperation.h"
#include "COM_ChunkOrder.h"
@@ -238,7 +239,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].determineDistance(hotspots, 1);
}
- sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
for (index = 0; index < this->m_numberOfChunks; index++) {
chunkOrder[index] = chunkOrders[index].getChunkNumber();
}
@@ -277,7 +278,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].determineDistance(hotspots, 9);
}
- sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
for (index = 0; index < this->m_numberOfChunks; index++) {
chunkOrder[index] = chunkOrders[index].getChunkNumber();
@@ -377,41 +378,12 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
return result;
}
-void ExecutionGroup::printBackgroundStats(void)
-{
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
- double execution_time;
- char timestr[64];
-
- execution_time = PIL_check_seconds_timer() - this->m_executionStartTime;
-
- mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
- peak_memory = MEM_get_peak_memory();
-
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
- megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
-
- fprintf(stdout, "Mem:%.2fM (%.2fM, Peak %.2fM) ",
- megs_used_memory, mmap_used_memory, megs_peak_memory);
-
- BLI_timestr(execution_time, timestr, sizeof(timestr));
- printf("| Elapsed %s ", timestr);
- printf("| Tree %s, Tile %u-%u ", this->m_bTree->id.name + 2,
- this->m_chunksFinished, this->m_numberOfChunks);
-
- fputc('\n', stdout);
- fflush(stdout);
-}
-
void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
{
if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
- this->m_chunksFinished++;
+ atomic_add_u(&this->m_chunksFinished, 1);
if (memoryBuffers) {
for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
@@ -430,8 +402,11 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
progress /= this->m_numberOfChunks;
this->m_bTree->progress(this->m_bTree->prh, progress);
- if (G.background)
- printBackgroundStats();
+ char buf[128];
+ BLI_snprintf(buf, sizeof(buf), "Compositing | Tile %u-%u",
+ this->m_chunksFinished,
+ this->m_numberOfChunks);
+ this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
}
}
@@ -459,7 +434,8 @@ void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumb
determineChunkRect(rect, xChunk, yChunk);
}
-MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int chunkNumber, rcti *rect)
+MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/,
+ rcti *rect)
{
// we asume that this method is only called from complex execution groups.
NodeOperation *operation = this->getOutputOperation();
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index 4b6f51c72c0..99365cdd4a8 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -347,11 +347,6 @@ public:
MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
/**
- * @brief print execution statistics to stdout when running in a background mode
- */
- void printBackgroundStats(void);
-
- /**
* @brief after a chunk is executed the needed resources can be freed or unlocked.
* @param chunknumber
* @param memorybuffers
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
index 0667271f4b1..caeaa07d9f9 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
@@ -43,8 +43,10 @@ extern "C" {
#endif
ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
{
+ this->m_context.setViewName(viewName);
this->m_context.setScene(scene);
this->m_context.setbNodeTree(editingtree);
this->m_context.setPreviewHash(editingtree->previews);
@@ -76,6 +78,8 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editin
viewer_border->xmin < viewer_border->xmax &&
viewer_border->ymin < viewer_border->ymax;
+ editingtree->stats_draw(editingtree->sdh, "Compositing | Determining resolution");
+
for (index = 0; index < this->m_groups.size(); index++) {
resolution[0] = 0;
resolution[1] = 0;
@@ -124,6 +128,9 @@ void ExecutionSystem::set_operations(const Operations &operations, const Groups
void ExecutionSystem::execute()
{
+ const bNodeTree *editingtree = this->m_context.getbNodeTree();
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Initializing execution");
+
DebugInfo::execute_started(this);
unsigned int order = 0;
@@ -178,6 +185,7 @@ void ExecutionSystem::execute()
WorkScheduler::finish();
WorkScheduler::stop();
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Deinitializing execution");
for (index = 0; index < this->m_operations.size(); index++) {
NodeOperation *operation = this->m_operations[index];
operation->deinitExecution();
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index ab903206f0a..41d63fb3a72 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -27,14 +27,11 @@ class ExecutionGroup;
#include "DNA_color_types.h"
#include "DNA_node_types.h"
-#include <vector>
#include "COM_Node.h"
#include "BKE_text.h"
#include "COM_ExecutionGroup.h"
#include "COM_NodeOperation.h"
-using namespace std;
-
/**
* @page execution Execution model
* In order to get to an efficient model for execution, several steps are being done. these steps are explained below.
@@ -154,7 +151,8 @@ public:
* @param rendering [true false]
*/
ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
/**
* Destructor
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
index 9e6e5a423f9..2dbf0a6aa46 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
@@ -64,7 +64,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, r
this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
this->m_state = COM_MB_ALLOCATED;
- this->m_datatype = memoryProxy->getDataType();;
+ this->m_datatype = memoryProxy->getDataType();
}
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index d9c16615fb6..7c87524b4b3 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -161,7 +161,7 @@ public:
*
* @return bool the result of this method
*/
- virtual bool isOutputOperation(bool rendering) const { return false; }
+ virtual bool isOutputOperation(bool /*rendering*/) const { return false; }
virtual int isSingleThreaded() { return false; }
@@ -175,7 +175,8 @@ public:
* @param chunkNumber the chunkNumber to be calculated
* @param memoryBuffers all input MemoryBuffer's needed
*/
- virtual void executeRegion(rcti *rect, unsigned int chunkNumber) {}
+ virtual void executeRegion(rcti * /*rect*/,
+ unsigned int /*chunkNumber*/) {}
/**
* @brief when a chunk is executed by an OpenCLDevice, this method is called
@@ -189,8 +190,11 @@ public:
* @param memoryBuffers all input MemoryBuffer's needed
* @param outputBuffer the outputbuffer to write to
*/
- virtual void executeOpenCLRegion(OpenCLDevice *device, rcti *rect,
- unsigned int chunkNumber, MemoryBuffer **memoryBuffers, MemoryBuffer *outputBuffer) {}
+ virtual void executeOpenCLRegion(OpenCLDevice * /*device*/,
+ rcti * /*rect*/,
+ unsigned int /*chunkNumber*/,
+ MemoryBuffer ** /*memoryBuffers*/,
+ MemoryBuffer * /*outputBuffer*/) {}
/**
* @brief custom handle to add new tasks to the OpenCL command queue in order to execute a chunk on an GPUDevice
@@ -204,10 +208,12 @@ public:
* @param clMemToCleanUp all created cl_mem references must be added to this list. Framework will clean this after execution
* @param clKernelsToCleanUp all created cl_kernel references must be added to this list. Framework will clean this after execution
*/
- virtual void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp) {}
+ virtual void executeOpenCL(OpenCLDevice * /*device*/,
+ MemoryBuffer * /*outputMemoryBuffer*/,
+ cl_mem /*clOutputBuffer*/,
+ MemoryBuffer ** /*inputMemoryBuffers*/,
+ list<cl_mem> * /*clMemToCleanUp*/,
+ list<cl_kernel> * /*clKernelsToCleanUp*/) {}
virtual void deinitExecution();
bool isResolutionSet() {
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index 74c05c3e62e..e899b7b14fd 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -101,12 +101,12 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
}
}
- add_datatype_conversions();
-
add_operation_input_constants();
resolve_proxies();
+ add_datatype_conversions();
+
determineResolutions();
/* surround complex ops with read/write buffer */
@@ -459,7 +459,8 @@ WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation
return NULL;
}
-void NodeOperationBuilder::add_input_buffers(NodeOperation *operation, NodeOperationInput *input)
+void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/,
+ NodeOperationInput *input)
{
if (!input->isConnected())
return;
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
index c300a85bfa3..b17f5d6b429 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
@@ -33,7 +33,7 @@ void SingleThreadedOperation::initExecution()
initMutex();
}
-void SingleThreadedOperation::executePixel(float output[4], int x, int y, void *data)
+void SingleThreadedOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
this->m_cachedInstance->readNoCheck(output, x, y);
}
diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h
index c996ef5bbeb..7ba208ebbf6 100644
--- a/source/blender/compositor/intern/COM_SocketReader.h
+++ b/source/blender/compositor/intern/COM_SocketReader.h
@@ -63,7 +63,10 @@ protected:
* @param y the y-coordinate of the pixel to calculate in image space
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) {}
+ virtual void executePixelSampled(float /*output*/[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/) { }
/**
* @brief calculate a single pixel
@@ -74,7 +77,7 @@ protected:
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
* @param chunkData chunk specific data a during execution time.
*/
- virtual void executePixel(float output[4], int x, int y, void *chunkData) {
+ virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/) {
executePixelSampled(output, x, y, COM_PS_NEAREST);
}
@@ -88,7 +91,10 @@ protected:
* @param dy
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) {}
+ virtual void executePixelFiltered(float /*output*/[4],
+ float /*x*/, float /*y*/,
+ float /*dx*/[2], float /*dy*/[2],
+ PixelSampler /*sampler*/) {}
public:
inline void readSampled(float result[4], float x, float y, PixelSampler sampler) {
@@ -101,12 +107,12 @@ public:
executePixelFiltered(result, x, y, dx, dy, sampler);
}
- virtual void *initializeTileData(rcti *rect) { return 0; }
- virtual void deinitializeTileData(rcti *rect, void *data) {}
+ virtual void *initializeTileData(rcti * /*rect*/) { return 0; }
+ virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/) {}
virtual ~SocketReader() {}
- virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) { return 0; }
+ virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/) { return 0; }
inline const unsigned int getWidth() const { return this->m_width; }
inline const unsigned int getHeight() const { return this->m_height; }
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 673920ef84a..fc6ea1299cf 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -276,7 +276,10 @@ bool WorkScheduler::hasGPUDevices()
#endif
}
-static void CL_CALLBACK clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data)
+static void CL_CALLBACK clContextError(const char *errinfo,
+ const void * /*private_info*/,
+ size_t /*cb*/,
+ void * /*user_data*/)
{
printf("OPENCL error: %s\n", errinfo);
}
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index ec9ef6c7e68..7f7fc141aca 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -45,7 +45,8 @@ static void intern_freeCompositorCaches()
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
{
/* initialize mutex, TODO this mutex init is actually not thread safe and
* should be done somewhere as part of blender startup, all the other
@@ -77,11 +78,12 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
/* set progress bar to 0% and status to init compositing */
editingtree->progress(editingtree->prh, 0.0);
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing");
bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering;
/* initialize execution system */
if (twopass) {
- ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings);
+ ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings, viewName);
system->execute();
delete system;
@@ -94,7 +96,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
}
ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, false,
- viewSettings, displaySettings);
+ viewSettings, displaySettings, viewName);
system->execute();
delete system;
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
index 0306d636c8b..e9b99b6aaf1 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
@@ -30,7 +30,7 @@
#include "COM_SetValueOperation.h"
#include "DNA_material_types.h" // the ramp types
-void AlphaOverNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void AlphaOverNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *color1Socket = this->getInputSocket(1);
NodeInput *color2Socket = this->getInputSocket(2);
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cpp
index c75e9b16336..7b7cfc812aa 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.cpp
@@ -29,7 +29,7 @@ BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void BokehImageNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void BokehImageNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
BokehImageOperation *operation = new BokehImageOperation();
operation->setData((NodeBokehImage *)this->getbNode()->storage);
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
index e684b569945..053f286c66e 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
@@ -29,7 +29,7 @@ BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
BrightnessOperation *operation = new BrightnessOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
index f356c74cd49..b04f86dea08 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
@@ -30,7 +30,7 @@ ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
index 90de9358587..6324ca9a3ca 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
@@ -30,7 +30,7 @@ ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ChromaMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ChromaMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
index fc0df046e86..a531493d486 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
@@ -32,7 +32,7 @@ ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
NodeColorBalance *n = (NodeColorBalance *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
index 728b51b8dc1..e926d131c1a 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
@@ -29,7 +29,7 @@ ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorCorrectionNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorCorrectionNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
index 6dc936302f4..5a4dc79e6b2 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
@@ -29,7 +29,7 @@ ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
if (this->getInputSocket(2)->isLinked() || this->getInputSocket(3)->isLinked()) {
ColorCurveOperation *operation = new ColorCurveOperation();
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
index def3b18e0fe..f7c20894087 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
@@ -30,7 +30,7 @@ ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cpp
index 4106cb64798..c3770e79dea 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorNode.cpp
@@ -29,7 +29,7 @@ ColorNode::ColorNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetColorOperation *operation = new SetColorOperation();
NodeOutput *output = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cpp
index a61ddffbf35..1feaa88bebb 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.cpp
@@ -32,7 +32,7 @@ ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorRampNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorRampNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
index 82454ba7979..c3a911e830b 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
@@ -29,7 +29,7 @@ ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorSpillNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorSpillNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
index a1616a61b4b..f09c6bac3ee 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
@@ -30,7 +30,7 @@ ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorToBWNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorToBWNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *colorSocket = this->getInputSocket(0);
NodeOutput *valueSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cpp
index c7a3baf809d..a39e946fe5f 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cpp
@@ -72,17 +72,17 @@ void CombineColorNode::convertToOperations(NodeConverter &converter, const Compo
}
-NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext &/*context*/) const
{
return NULL; /* no conversion needed */
}
-NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertHSVToRGBOperation();
}
-NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &/*context*/) const
{
ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
bNode *editorNode = this->getbNode();
@@ -90,7 +90,7 @@ NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &conte
return operation;
}
-NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertYUVToRGBOperation();
}
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp
index 933b8d0282b..9e8b40d8af4 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp
@@ -43,6 +43,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi
CompositorOperation *compositorOperation = new CompositorOperation();
compositorOperation->setSceneName(context.getScene()->id.name);
compositorOperation->setRenderData(context.getRenderData());
+ compositorOperation->setViewName(context.getViewName());
compositorOperation->setbNodeTree(context.getbNodeTree());
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
compositorOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
index ba31ed6e89c..fbf5dbb6253 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
@@ -23,7 +23,7 @@
#include "COM_ConvertOperation.h"
#include "COM_ExecutionSystem.h"
-void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOperation *operation = NULL;
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
index ea9f22f2840..5e4e463595a 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
@@ -28,7 +28,7 @@ CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode)
{
}
-void CornerPinNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void CornerPinNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *input_image = this->getInputSocket(0);
/* note: socket order differs between UI node and operations:
diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cpp
index 6c3dc93481b..ee148f41c68 100644
--- a/source/blender/compositor/nodes/COM_CropNode.cpp
+++ b/source/blender/compositor/nodes/COM_CropNode.cpp
@@ -29,7 +29,7 @@ CropNode::CropNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void CropNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void CropNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = getbNode();
NodeTwoXYs *cropSettings = (NodeTwoXYs *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cpp
index bac6337374f..a21885bf42d 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.cpp
@@ -29,7 +29,7 @@ DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DespeckleNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DespeckleNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
NodeInput *inputSocket = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
index 8870badab09..2cb0e2301ac 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
@@ -30,7 +30,7 @@ DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DifferenceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DifferenceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputSocket2 = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
index 704c704c500..5f3feda5de7 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
@@ -31,7 +31,7 @@ DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DistanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DistanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
NodeChroma *storage = (NodeChroma *)editorsnode->storage;
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
index 1f80eeadf83..c67abb1ab99 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
@@ -29,7 +29,7 @@ DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
DoubleEdgeMaskOperation *operation;
bNode *bnode = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp
index 9f3a7ae795c..7493f24ba6b 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cpp
@@ -32,7 +32,7 @@ FilterNode::FilterNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void FilterNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void FilterNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputImageSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cpp
index 1dbcc97143e..0177dc7017a 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.cpp
+++ b/source/blender/compositor/nodes/COM_FlipNode.cpp
@@ -30,7 +30,7 @@ FlipNode::FlipNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void FlipNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void FlipNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cpp
index 046cd9e9a0d..bf24bee55d3 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.cpp
+++ b/source/blender/compositor/nodes/COM_GammaNode.cpp
@@ -29,7 +29,7 @@ GammaNode::GammaNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void GammaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void GammaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
GammaOperation *operation = new GammaOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cpp
index 0429a1a80cf..7afe1510ae4 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.cpp
+++ b/source/blender/compositor/nodes/COM_GlareNode.cpp
@@ -36,7 +36,7 @@ GlareNode::GlareNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void GlareNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void GlareNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
NodeGlare *glare = (NodeGlare *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
index 003bc91edd3..e159886bb46 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
@@ -36,7 +36,7 @@ HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode)
/* pass */
}
-void HueSaturationValueCorrectNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void HueSaturationValueCorrectNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *colorSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
index cdec1250c6e..29c296a896d 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
@@ -35,7 +35,7 @@ HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorN
/* pass */
}
-void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *colorSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index cb7ccfaedf9..572e63a2ced 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -40,19 +40,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode)
}
NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
- int framenumber, int outputsocketIndex, int passindex, DataType datatype) const
+ int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const
{
NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex);
MultilayerBaseOperation *operation = NULL;
switch (datatype) {
case COM_DT_VALUE:
- operation = new MultilayerValueOperation(passindex);
+ operation = new MultilayerValueOperation(passtype, view);
break;
case COM_DT_VECTOR:
- operation = new MultilayerVectorOperation(passindex);
+ operation = new MultilayerVectorOperation(passtype, view);
break;
case COM_DT_COLOR:
- operation = new MultilayerColorOperation(passindex);
+ operation = new MultilayerColorOperation(passtype, view);
break;
default:
break;
@@ -79,7 +79,6 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int numberOfOutputs = this->getNumberOfOutputSockets();
bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
BKE_image_user_frame_calc(imageuser, context.getFramenumber(), 0);
- NodeOperation *combined_operation = NULL;
/* force a load, we assume iuser index will be set OK anyway */
if (image && image->type == IMA_TYPE_MULTILAYER) {
bool is_multilayer_ok = false;
@@ -96,6 +95,9 @@ 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));
+ 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.
*/
@@ -104,47 +106,57 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int passindex = storage->pass_index;*/
RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
#endif
- int passindex;
- RenderPass *rpass;
- if (STREQ(bnodeSocket->identifier, "Alpha")) {
- BLI_assert(combined_operation != NULL);
- NodeOutput *outputSocket = this->getOutputSocket(index);
- SeparateChannelOperation *separate_operation;
- separate_operation = new SeparateChannelOperation();
- separate_operation->setChannel(3);
- converter.addOperation(separate_operation);
- converter.addLink(combined_operation->getOutputSocket(), separate_operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket());
- operation = separate_operation;
+
+ /* returns the image view to use for the current active view */
+ if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
+ const int view_image = imageuser->view;
+ const bool is_allview = (view_image == 0); /* if view selected == All (0) */
+
+ if (is_allview) {
+ /* heuristic to match image name with scene names
+ * check if the view name exists in the image */
+ view = BLI_findstringindex(&image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ if (view == -1) view = 0;
+ }
+ else {
+ view = view_image - 1;
+ }
}
- else {
- for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex)
- if (STREQ(rpass->name, bnodeSocket->identifier))
+
+ if (rpass) {
+ switch (rpass->channels) {
+ case 1:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_VALUE);
break;
- if (rpass) {
- imageuser->pass = passindex;
- switch (rpass->channels) {
- case 1:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE);
- break;
- /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
- /* XXX any way to detect actual vector images? */
- case 3:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR);
- break;
- case 4:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR);
- break;
- default:
- /* dummy operation is added below */
- break;
- }
- if (index == 0 && operation) {
- converter.addPreview(operation->getOutputSocket());
- }
- if (STREQ(rpass->chan_id, "RGBA")) {
- combined_operation = operation;
- }
+ /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
+ /* XXX any way to detect actual vector images? */
+ case 3:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_VECTOR);
+ break;
+ case 4:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_COLOR);
+ break;
+ default:
+ /* dummy operation is added below */
+ break;
+ }
+ 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++;
}
}
@@ -168,6 +180,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
operation->setImage(image);
operation->setImageUser(imageuser);
operation->setFramenumber(framenumber);
+ operation->setRenderData(context.getRenderData());
+ operation->setViewName(context.getViewName());
converter.addOperation(operation);
if (outputStraightAlpha) {
@@ -190,6 +204,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
alphaOperation->setImage(image);
alphaOperation->setImageUser(imageuser);
alphaOperation->setFramenumber(framenumber);
+ alphaOperation->setRenderData(context.getRenderData());
+ alphaOperation->setViewName(context.getViewName());
converter.addOperation(alphaOperation);
converter.mapOutputSocket(alphaImage, alphaOperation->getOutputSocket());
@@ -200,6 +216,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
depthOperation->setImage(image);
depthOperation->setImageUser(imageuser);
depthOperation->setFramenumber(framenumber);
+ depthOperation->setRenderData(context.getRenderData());
+ depthOperation->setViewName(context.getViewName());
converter.addOperation(depthOperation);
converter.mapOutputSocket(depthImage, depthOperation->getOutputSocket());
@@ -239,6 +257,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
}
if (operation) {
+ /* not supporting multiview for this generic case */
converter.addOperation(operation);
converter.mapOutputSocket(output, operation->getOutputSocket());
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 1daa39a2a1f..267794510e1 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -36,7 +36,7 @@ extern "C" {
class ImageNode : public Node {
private:
NodeOperation *doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
- int framenumber, int outputsocketIndex, int passindex, DataType datatype) const;
+ int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const;
public:
ImageNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cpp
index 1371cdb5f1d..9e78625684d 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.cpp
+++ b/source/blender/compositor/nodes/COM_InpaintNode.cpp
@@ -31,7 +31,7 @@ InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void InpaintNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void InpaintNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cpp
index ed4a21132ca..da499d66c2c 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.cpp
+++ b/source/blender/compositor/nodes/COM_InvertNode.cpp
@@ -30,7 +30,7 @@ InvertNode::InvertNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void InvertNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void InvertNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
InvertOperation *operation = new InvertOperation();
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
index 32db452e6c2..3d3cc841715 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
@@ -30,7 +30,7 @@ LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void LensDistortionNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void LensDistortionNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
NodeLensDist *data = (NodeLensDist *)editorNode->storage;
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
index e23ec243ff4..382296a7f3a 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
@@ -30,7 +30,7 @@ LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
NodeInput *inputSocket = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cpp
index 2c164cfad32..148ca00205c 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.cpp
@@ -30,7 +30,7 @@ MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapRangeNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapRangeNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *sourceMinSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cpp
index 25ca7b8b8c6..ec38e23ec07 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapUVNode.cpp
@@ -28,7 +28,7 @@ MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapUVNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapUVNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cpp
index d7ee4e6a38b..f04c6a2d316 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapValueNode.cpp
@@ -30,7 +30,7 @@ MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
TexMapping *storage = (TexMapping *)this->getbNode()->storage;
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp
index 4cd6964ed3b..eb6bb2caf56 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cpp
@@ -24,7 +24,7 @@
#include "COM_MathBaseOperation.h"
#include "COM_ExecutionSystem.h"
-void MathNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MathNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
MathBaseOperation *operation = NULL;
diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cpp
index 89010d0e861..0607d6d6705 100644
--- a/source/blender/compositor/nodes/COM_MixNode.cpp
+++ b/source/blender/compositor/nodes/COM_MixNode.cpp
@@ -34,7 +34,7 @@ MixNode::MixNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MixNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MixNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *color1Socket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cpp
index d7c3fd11844..26da61cb9e7 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalNode.cpp
@@ -31,7 +31,7 @@ NormalNode::NormalNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void NormalNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void NormalNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cpp
index f6e919c168f..a13fcd2a301 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.cpp
@@ -28,7 +28,7 @@ NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void NormalizeNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void NormalizeNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NormalizeOperation *operation = new NormalizeOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
index 92fa74b9a2e..42805d1ff37 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
@@ -23,8 +23,11 @@
#include "COM_OutputFileNode.h"
#include "COM_OutputFileOperation.h"
+#include "COM_OutputFileMultiViewOperation.h"
#include "COM_ExecutionSystem.h"
+#include "BKE_scene.h"
+
#include "BLI_path_util.h"
OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
@@ -35,6 +38,7 @@ OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
void OutputFileNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
NodeImageMultiFile *storage = (NodeImageMultiFile *)this->getbNode()->storage;
+ const bool is_multiview = (context.getRenderData()->scemode & R_MULTIVIEW) != 0;
if (!context.isRendering()) {
/* only output files when rendering a sequence -
@@ -43,13 +47,24 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
*/
return;
}
-
+
if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ const bool use_half_float = (storage->format.depth == R_IMF_CHAN_DEPTH_16);
/* single output operation for the multilayer file */
- OutputOpenExrMultiLayerOperation *outputOperation = new OutputOpenExrMultiLayerOperation(
- context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec);
+ OutputOpenExrMultiLayerOperation *outputOperation;
+
+ if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) {
+ outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(
+ context.getRenderData(), context.getbNodeTree(), storage->base_path,
+ storage->format.exr_codec, use_half_float, context.getViewName());
+ }
+ else {
+ outputOperation = new OutputOpenExrMultiLayerOperation(
+ context.getRenderData(), context.getbNodeTree(), storage->base_path,
+ storage->format.exr_codec, use_half_float, context.getViewName());
+ }
converter.addOperation(outputOperation);
-
+
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
for (int i = 0; i < num_inputs; ++i) {
@@ -76,17 +91,31 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
ImageFormatData *format = (sockdata->use_node_format ? &storage->format : &sockdata->format);
char path[FILE_MAX];
-
+
/* combine file path for the input */
BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
-
- OutputSingleLayerOperation *outputOperation = new OutputSingleLayerOperation(
- context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
- context.getViewSettings(), context.getDisplaySettings());
+
+ NodeOperation *outputOperation = NULL;
+
+ if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
+ outputOperation = new OutputOpenExrSingleLayerMultiViewOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+ else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ outputOperation = new OutputSingleLayerOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ outputOperation = new OutputStereoOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ sockdata->layer, context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+
converter.addOperation(outputOperation);
-
converter.mapInputSocket(input, outputOperation->getInputSocket(0));
-
+
if (!previewAdded) {
converter.addNodeInputPreview(input);
previewAdded = true;
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cpp
index da3cd74e771..fe806dbf307 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.cpp
+++ b/source/blender/compositor/nodes/COM_PixelateNode.cpp
@@ -30,7 +30,7 @@ PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void PixelateNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void PixelateNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
index 71e6ab12dfc..653100ce6a4 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -20,7 +20,6 @@
*/
#include "COM_Node.h"
-#include "DNA_node_types.h"
extern "C" {
# include "DNA_movieclip_types.h"
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index cc66c688379..02bf1ec8cfb 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -42,7 +42,8 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor
operation->setScene(scene);
operation->setLayerId(layerId);
operation->setRenderData(context.getRenderData());
-
+ operation->setViewName(context.getViewName());
+
converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cpp
index c5fe88b3636..6fd7e357775 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.cpp
+++ b/source/blender/compositor/nodes/COM_RotateNode.cpp
@@ -31,7 +31,7 @@ RotateNode::RotateNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void RotateNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void RotateNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputDegreeSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
index a6fa9065364..780ce73d340 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
@@ -96,17 +96,17 @@ void SeparateColorNode::convertToOperations(NodeConverter &converter, const Comp
}
-NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext &/*context*/) const
{
return NULL; /* no conversion needed */
}
-NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertRGBToHSVOperation();
}
-NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &/*context*/) const
{
ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
bNode *editorNode = this->getbNode();
@@ -114,7 +114,7 @@ NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &cont
return operation;
}
-NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertRGBToYUVOperation();
}
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
index 22ddd5bb157..32c03c695be 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
@@ -24,7 +24,7 @@
#include "COM_SetAlphaOperation.h"
#include "COM_ExecutionSystem.h"
-void SetAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SetAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetAlphaOperation *operation = new SetAlphaOperation();
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
index 17b00af16d8..465a94e8335 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
@@ -46,7 +46,7 @@ SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bN
this->addOutputSocket(dt, editorOutput);
}
-void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion);
converter.mapOutputSocket(getOutputSocket(), proxy_output);
@@ -68,7 +68,7 @@ SocketBufferNode::SocketBufferNode(bNode *editorNode, bNodeSocket *editorInput,
this->addOutputSocket(dt, editorOutput);
}
-void SocketBufferNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SocketBufferNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOutput *output = this->getOutputSocket(0);
NodeInput *input = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
index 15eca0a97e5..0f917d317f9 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
@@ -22,6 +22,8 @@
#include "COM_SplitViewerNode.h"
#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_scene.h"
#include "COM_SplitOperation.h"
#include "COM_ViewerOperation.h"
@@ -55,6 +57,8 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos
viewerOperation->setImageUser(imageUser);
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
+ viewerOperation->setRenderData(context.getRenderData());
+ viewerOperation->setViewName(context.getViewName());
/* defaults - the viewer node has these options but not exposed for split view
* we could use the split to define an area of interest on one axis at least */
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
index ed14acabf36..7cf3c90c786 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
@@ -27,7 +27,7 @@ SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cpp
index 10f0ee3821d..eb854983d4c 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cpp
@@ -27,7 +27,7 @@ SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bool condition = this->getbNode()->custom1;
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
new file mode 100644
index 00000000000..5a23b8b4d9e
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * 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:
+ * Dalai Felinto
+ */
+
+#include "COM_SwitchViewNode.h"
+#include "BLI_listbase.h"
+
+SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void SwitchViewNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+{
+ NodeOperationOutput *result;
+ const char *viewName = context.getViewName();
+ bNode *bnode = this->getbNode();
+
+ /* get the internal index of the socket with a matching name */
+ int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
+ nr = max(nr, 0);
+
+ result = converter.addInputProxy(getInputSocket(nr), false);
+ converter.mapOutputSocket(getOutputSocket(0), result);
+}
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.h b/source/blender/compositor/nodes/COM_SwitchViewNode.h
new file mode 100644
index 00000000000..6ab5145bed5
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * 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:
+ * Dalai Felinto
+ */
+
+#ifndef _COM_SwitchViewNode_h_
+#define _COM_SwitchViewNode_h_
+
+#include "COM_Node.h"
+#include "COM_NodeOperation.h"
+#include "DNA_node_types.h"
+/**
+ * @brief SwitchViewNode
+ * @ingroup Node
+ */
+class SwitchViewNode : public Node {
+public:
+ SwitchViewNode(bNode *editorNode);
+ void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+};
+#endif
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cpp
index 5ac73b9f9c2..961139d4855 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.cpp
+++ b/source/blender/compositor/nodes/COM_TonemapNode.cpp
@@ -29,7 +29,7 @@ TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void TonemapNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void TonemapNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeTonemap *data = (NodeTonemap *)this->getbNode()->storage;
diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cpp
index f1d5771bab3..148409a6427 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.cpp
+++ b/source/blender/compositor/nodes/COM_TransformNode.cpp
@@ -33,7 +33,7 @@ TransformNode::TransformNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void TransformNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void TransformNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *imageInput = this->getInputSocket(0);
NodeInput *xInput = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cpp
index 62a312da67c..c75d9296807 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_ValueNode.cpp
@@ -29,7 +29,7 @@ ValueNode::ValueNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetValueOperation *operation = new SetValueOperation();
NodeOutput *output = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
index 197b2c8bd0c..7222a018fa0 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
@@ -29,7 +29,7 @@ VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void VectorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void VectorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
VectorCurveOperation *operation = new VectorCurveOperation();
operation->setCurveMapping((CurveMapping *)this->getbNode()->storage);
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
index 30f51794e8d..06f12ccc559 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
@@ -31,7 +31,7 @@ ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ViewLevelsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ViewLevelsNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *input = this->getInputSocket(0);
if (input->isLinked()) {
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp
index ff0b8fb1706..ab819ce6e30 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cpp
@@ -22,6 +22,9 @@
#include "COM_ViewerNode.h"
#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BLI_listbase.h"
+#include "BKE_scene.h"
#include "COM_ViewerOperation.h"
#include "COM_ExecutionSystem.h"
@@ -51,6 +54,8 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC
viewerOperation->setCenterY(editorNode->custom4);
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
viewerOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
+ viewerOperation->setRenderData(context.getRenderData());
+ viewerOperation->setViewName(context.getViewName());
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
index b25e2281467..2e60c2d3e42 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
@@ -45,7 +45,7 @@ void AntiAliasOperation::initExecution()
NodeOperation::initMutex();
}
-void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data)
+void AntiAliasOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
if (y < 0 || (unsigned int)y >= this->m_height || x < 0 || (unsigned int)x >= this->m_width) {
output[0] = 0.0f;
@@ -66,7 +66,7 @@ void AntiAliasOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool AntiAliasOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_buffer) {
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index d5aafc7c2ae..ce42de7a149 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -92,7 +92,7 @@ float *BlurBaseOperation::make_gausstab(float rad, int size)
}
#ifdef __SSE2__
-__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, float rad, int size)
+__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
{
int n = 2 * size + 1;
__m128 *gausstab_sse = (__m128 *) MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse");
@@ -133,6 +133,9 @@ float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff
case PROP_SHARP:
val = val * val;
break;
+ case PROP_INVSQUARE:
+ val = val * (2.0f - val);
+ break;
case PROP_LIN:
/* fall-through */
#ifndef NDEBUG
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index e97dd4d766d..f9f37479c56 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -39,7 +39,7 @@ protected:
BlurBaseOperation(DataType data_type);
float *make_gausstab(float rad, int size);
#ifdef __SSE2__
- __m128 *convert_gausstab_sse(const float *gaustab, float rad, int size);
+ __m128 *convert_gausstab_sse(const float *gaustab, int size);
#endif
float *make_dist_fac_inverse(float rad, int size, int falloff);
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
index 22f6fc33a0d..189483708b5 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
@@ -45,7 +45,7 @@ BokehBlurOperation::BokehBlurOperation() : NodeOperation()
this->m_inputBoundingBoxReader = NULL;
}
-void *BokehBlurOperation::initializeTileData(rcti *rect)
+void *BokehBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -194,7 +194,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBuffe
void BokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", NULL);
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cpp
index 6617fc62ab8..18846f2a2c5 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cpp
@@ -85,7 +85,7 @@ float BokehImageOperation::isInsideBokeh(float distance, float x, float y)
}
return insideBokeh;
}
-void BokehImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void BokehImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float shift = this->m_data->lensshift;
float shift2 = shift / 2.0f;
@@ -116,7 +116,7 @@ void BokehImageOperation::deinitExecution()
}
}
-void BokehImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void BokehImageOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = COM_BLUR_BOKEH_PIXELS;
resolution[1] = COM_BLUR_BOKEH_PIXELS;
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
index a2954a20e90..d26dcd17750 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
@@ -24,7 +24,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
+extern "C" {
+#include "IMB_colormanagement.h"
+}
CalculateMeanOperation::CalculateMeanOperation() : NodeOperation()
{
@@ -42,7 +44,9 @@ void CalculateMeanOperation::initExecution()
NodeOperation::initMutex();
}
-void CalculateMeanOperation::executePixel(float output[4], int x, int y, void *data)
+void CalculateMeanOperation::executePixel(float output[4],
+ int /*x*/, int /*y*/,
+ void * /*data*/)
{
output[0] = this->m_result;
}
@@ -53,7 +57,7 @@ void CalculateMeanOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_iscalculated) {
@@ -96,7 +100,7 @@ void CalculateMeanOperation::calculateMean(MemoryBuffer *tile)
switch (this->m_setting) {
case 1:
{
- sum += rgb_to_bw(&buffer[offset]);
+ sum += IMB_colormanagement_get_luminance(&buffer[offset]);
break;
}
case 2:
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
index 0c67da2d552..6b238e53d7b 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
@@ -24,14 +24,18 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
+extern "C" {
+#include "IMB_colormanagement.h"
+}
CalculateStandardDeviationOperation::CalculateStandardDeviationOperation() : CalculateMeanOperation()
{
/* pass */
}
-void CalculateStandardDeviationOperation::executePixel(float output[4], int x, int y, void *data)
+void CalculateStandardDeviationOperation::executePixel(float output[4],
+ int /*x*/, int /*y*/,
+ void * /*data*/)
{
output[0] = this->m_standardDeviation;
}
@@ -55,7 +59,7 @@ void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect)
switch (this->m_setting) {
case 1: /* rgb combined */
{
- float value = rgb_to_bw(&buffer[offset]);
+ float value = IMB_colormanagement_get_luminance(&buffer[offset]);
sum += (value - mean) * (value - mean);
break;
}
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
index 19209951005..54e0fb41abf 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
@@ -23,6 +23,10 @@
#include "COM_ColorCorrectionOperation.h"
#include "BLI_math.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
ColorCorrectionOperation::ColorCorrectionOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
@@ -90,7 +94,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4], float x, flo
lift += (levelShadows * this->m_data->shadows.lift) + (levelMidtones * this->m_data->midtones.lift) + (levelHighlights * this->m_data->highlights.lift);
float invgamma = 1.0f / gamma;
- float luma = rgb_to_luma_y(inputImageColor);
+ float luma = IMB_colormanagement_get_luminance(inputImageColor);
r = inputImageColor[0];
g = inputImageColor[1];
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index e3438bcbd15..76f74c144f6 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -52,6 +52,7 @@ CompositorOperation::CompositorOperation() : NodeOperation()
this->m_active = false;
this->m_sceneName[0] = '\0';
+ this->m_viewName = NULL;
}
void CompositorOperation::initExecution()
@@ -81,14 +82,16 @@ void CompositorOperation::deinitExecution()
RenderResult *rr = RE_AcquireResultWrite(re);
if (rr) {
- if (rr->rectf != NULL) {
- MEM_freeN(rr->rectf);
+ RenderView *rv = RE_RenderViewGetByName(rr, this->m_viewName);
+
+ if (rv->rectf != NULL) {
+ MEM_freeN(rv->rectf);
}
- rr->rectf = this->m_outputBuffer;
- if (rr->rectz != NULL) {
- MEM_freeN(rr->rectz);
+ rv->rectf = this->m_outputBuffer;
+ if (rv->rectz != NULL) {
+ MEM_freeN(rv->rectz);
}
- rr->rectz = this->m_depthBuffer;
+ rv->rectz = this->m_depthBuffer;
}
else {
if (this->m_outputBuffer) {
@@ -125,7 +128,7 @@ void CompositorOperation::deinitExecution()
}
-void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
float color[8]; // 7 is enough
float *buffer = this->m_outputBuffer;
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h
index 771c32ffd12..e81ba520695 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.h
+++ b/source/blender/compositor/operations/COM_CompositorOperation.h
@@ -75,13 +75,19 @@ private:
* @brief operation is active for calculating final compo result
*/
bool m_active;
+
+ /**
+ * @brief View name, used for multiview
+ */
+ const char *m_viewName;
public:
CompositorOperation();
const bool isActiveCompositorOutput() const { return this->m_active; }
void executeRegion(rcti *rect, unsigned int tileNumber);
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; }
- bool isOutputOperation(bool rendering) const { return this->isActiveCompositorOutput(); }
+ bool isOutputOperation(bool /*rendering*/) const { return this->isActiveCompositorOutput(); }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_MEDIUM; }
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp
index 977586acb60..8b8e8408208 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cpp
@@ -22,6 +22,9 @@
#include "COM_ConvertOperation.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
ConvertBaseOperation::ConvertBaseOperation()
{
@@ -84,7 +87,7 @@ void ConvertColorToBWOperation::executePixelSampled(float output[4], float x, fl
{
float inputColor[4];
this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- output[0] = rgb_to_bw(inputColor);
+ output[0] = IMB_colormanagement_get_luminance(inputColor);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
index 657126d458c..e1ada9a8c39 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
@@ -28,7 +28,7 @@ ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation() : ConvolutionFi
/* pass */
}
-void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void *data)
+void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0};
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
index 553a9827ffa..699db11d56e 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
@@ -69,7 +69,7 @@ void ConvolutionFilterOperation::deinitExecution()
}
-void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void *data)
+void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4];
float in2[4];
diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp
index 9bcc6fb2541..e5427589fce 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cpp
+++ b/source/blender/compositor/operations/COM_CropOperation.cpp
@@ -36,27 +36,28 @@ void CropBaseOperation::updateArea()
SocketReader *inputReference = this->getInputSocketReader(0);
float width = inputReference->getWidth();
float height = inputReference->getHeight();
+ NodeTwoXYs local_settings = *this->m_settings;
if (width > 0.0f && height > 0.0f) {
if (this->m_relative) {
- this->m_settings->x1 = width * this->m_settings->fac_x1;
- this->m_settings->x2 = width * this->m_settings->fac_x2;
- this->m_settings->y1 = height * this->m_settings->fac_y1;
- this->m_settings->y2 = height * this->m_settings->fac_y2;
+ local_settings.x1 = width * local_settings.fac_x1;
+ local_settings.x2 = width * local_settings.fac_x2;
+ local_settings.y1 = height * local_settings.fac_y1;
+ local_settings.y2 = height * local_settings.fac_y2;
}
- if (width <= this->m_settings->x1 + 1)
- this->m_settings->x1 = width - 1;
- if (height <= this->m_settings->y1 + 1)
- this->m_settings->y1 = height - 1;
- if (width <= this->m_settings->x2 + 1)
- this->m_settings->x2 = width - 1;
- if (height <= this->m_settings->y2 + 1)
- this->m_settings->y2 = height - 1;
+ if (width <= local_settings.x1 + 1)
+ local_settings.x1 = width - 1;
+ if (height <= local_settings.y1 + 1)
+ local_settings.y1 = height - 1;
+ if (width <= local_settings.x2 + 1)
+ local_settings.x2 = width - 1;
+ if (height <= local_settings.y2 + 1)
+ local_settings.y2 = height - 1;
- this->m_xmax = max(this->m_settings->x1, this->m_settings->x2) + 1;
- this->m_xmin = min(this->m_settings->x1, this->m_settings->x2);
- this->m_ymax = max(this->m_settings->y1, this->m_settings->y2) + 1;
- this->m_ymin = min(this->m_settings->y1, this->m_settings->y2);
+ this->m_xmax = max(local_settings.x1, local_settings.x2) + 1;
+ this->m_xmin = min(local_settings.x1, local_settings.x2);
+ this->m_ymax = max(local_settings.y1, local_settings.y2) + 1;
+ this->m_ymin = min(local_settings.y1, local_settings.y2);
}
else {
this->m_xmax = 0;
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cpp
index 186c17845f3..1a827aae67e 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.cpp
@@ -52,7 +52,7 @@ BLI_INLINE int color_diff(const float a[3], const float b[3], const float thresh
(fabsf(a[2] - b[2]) > threshold));
}
-void DespeckleOperation::executePixel(float output[4], int x, int y, void *data)
+void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float w = 0.0f;
float color_org[4];
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index 6d15ef3395b..fc3ec7dd11a 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -56,7 +56,7 @@ void DilateErodeThresholdOperation::initExecution()
}
}
-void *DilateErodeThresholdOperation::initializeTileData(rcti *rect)
+void *DilateErodeThresholdOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
return buffer;
@@ -180,7 +180,7 @@ void DilateDistanceOperation::initExecution()
}
}
-void *DilateDistanceOperation::initializeTileData(rcti *rect)
+void *DilateDistanceOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
return buffer;
@@ -238,7 +238,7 @@ bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input, Read
void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", NULL);
@@ -295,7 +295,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", NULL);
@@ -446,7 +446,7 @@ void DilateStepOperation::deinitExecution()
this->m_inputProgram = NULL;
}
-void DilateStepOperation::deinitializeTileData(rcti *rect, void *data)
+void DilateStepOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
tile_info *tile = (tile_info *)data;
MEM_freeN(tile->buffer);
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 962a95ebd05..732e731fadf 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -66,7 +66,7 @@ void DirectionalBlurOperation::initExecution()
}
-void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
const int iterations = pow(2.0f, this->m_data->iter);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -104,7 +104,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", NULL);
@@ -132,7 +132,7 @@ void DirectionalBlurOperation::deinitExecution()
this->m_inputProgram = NULL;
}
-bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
index 7dacc3239c5..6dfef8a0a11 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
@@ -49,15 +49,19 @@ void DisplaceOperation::initExecution()
this->m_height_x4 = this->getHeight() * 4;
}
-void DisplaceOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void DisplaceOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float xy[2] = { x, y };
float uv[2], deriv[2][2];
pixelTransform(xy, uv, deriv);
-
- /* EWA filtering (without nearest it gets blurry with NO distortion) */
- this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
+ if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
+ this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR);
+ }
+ else {
+ /* EWA filtering (without nearest it gets blurry with NO distortion) */
+ this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
+ }
}
bool DisplaceOperation::read_displacement(float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v)
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 234a61a4c41..76afedf4b2a 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -1237,7 +1237,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() : NodeOperation()
this->setComplex(true);
}
-bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cachedInstance == NULL) {
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 08f520e4271..968319b3f46 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -37,7 +37,7 @@ void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void
newData->read(output, x, y);
}
-bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
rcti sizeInput;
@@ -257,7 +257,7 @@ void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y,
newData->read(output, x, y);
}
-bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
index dde57ab640f..cbe41076b2a 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
@@ -36,7 +36,7 @@ GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(C
this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */
}
-void *GaussianAlphaXBlurOperation::initializeTileData(rcti *rect)
+void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
index bb5b3c044af..30563e8cc45 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
@@ -36,7 +36,7 @@ GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(C
this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */
}
-void *GaussianAlphaYBlurOperation::initializeTileData(rcti *rect)
+void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index dbad51c4329..37d59229e50 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -32,7 +32,7 @@ GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM
this->m_gausstab = NULL;
}
-void *GaussianBokehBlurOperation::initializeTileData(rcti *rect)
+void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -205,7 +205,7 @@ GaussianBlurReferenceOperation::GaussianBlurReferenceOperation() : BlurBaseOpera
this->m_maintabs = NULL;
}
-void *GaussianBlurReferenceOperation::initializeTileData(rcti *rect)
+void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = getInputOperation(0)->initializeTileData(NULL);
return buffer;
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
index 0838d281de7..29ed4334412 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
@@ -38,7 +38,7 @@ GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLO
this->m_filtersize = 0;
}
-void *GaussianXBlurOperation::initializeTileData(rcti *rect)
+void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -63,7 +63,6 @@ void GaussianXBlurOperation::initExecution()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -79,7 +78,6 @@ void GaussianXBlurOperation::updateGauss()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -128,7 +126,7 @@ void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *d
void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel("gaussianXBlurOperationKernel", NULL);
cl_int filter_size = this->m_filtersize;
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
index 6172f954087..4b55333c08c 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
@@ -38,7 +38,7 @@ GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLO
this->m_filtersize = 0;
}
-void *GaussianYBlurOperation::initializeTileData(rcti *rect)
+void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -62,7 +62,6 @@ void GaussianYBlurOperation::initExecution()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -78,7 +77,6 @@ void GaussianYBlurOperation::updateGauss()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -130,7 +128,7 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d
void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel("gaussianYBlurOperationKernel", NULL);
cl_int filter_size = this->m_filtersize;
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
index 98919f1b161..1acbd2ae090 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
@@ -55,7 +55,7 @@ MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2)
return result;
}
-bool GlareBaseOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (isCached()) {
return false;
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
index 69b5bd7d6bf..eea6588a9a6 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
@@ -65,7 +65,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
if (isBreaked()) breaked = true;
if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 2, 3);
- if (settings->iter & 1) ofs = 0.5f; else ofs = 0.f;
+ ofs = (settings->iter & 1) ? 0.5f : 0.0f;
for (x = 0; x < (settings->iter * 4); x++) {
y = x & 3;
cm[x][0] = cm[x][1] = cm[x][2] = 1;
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
index 78e1e80cafc..d2bd7cbeeab 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
@@ -23,6 +23,10 @@
#include "COM_GlareThresholdOperation.h"
#include "BLI_math.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
GlareThresholdOperation::GlareThresholdOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR, COM_SC_FIT);
@@ -47,7 +51,7 @@ void GlareThresholdOperation::executePixelSampled(float output[4], float x, floa
const float threshold = this->m_settings->threshold;
this->m_inputProgram->readSampled(output, x, y, sampler);
- if (rgb_to_luma_y(output) >= threshold) {
+ if (IMB_colormanagement_get_luminance(output) >= threshold) {
output[0] -= threshold, output[1] -= threshold, output[2] -= threshold;
output[0] = max(output[0], 0.0f);
output[1] = max(output[1], 0.0f);
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 2733c483146..c55366ab370 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -25,6 +25,7 @@
#include "BLI_listbase.h"
#include "DNA_image_types.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
#include "BLI_math.h"
extern "C" {
@@ -48,6 +49,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation()
this->m_framenumber = 0;
this->m_depthBuffer = NULL;
this->m_numberOfChannels = 0;
+ this->m_rd = NULL;
+ this->m_viewName = NULL;
}
ImageOperation::ImageOperation() : BaseImageOperation()
{
@@ -65,8 +68,16 @@ ImageDepthOperation::ImageDepthOperation() : BaseImageOperation()
ImBuf *BaseImageOperation::getImBuf()
{
ImBuf *ibuf;
-
- ibuf = BKE_image_acquire_ibuf(this->m_image, this->m_imageUser, NULL);
+ ImageUser iuser = *this->m_imageUser;
+
+ if (this->m_image == NULL)
+ return NULL;
+
+ /* local changes to the original ImageUser */
+ if (BKE_image_is_multilayer(this->m_image) == false)
+ iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+
+ ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, NULL);
if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
BKE_image_release_ibuf(this->m_image, ibuf, NULL);
return NULL;
@@ -96,7 +107,7 @@ void BaseImageOperation::deinitExecution()
BKE_image_release_ibuf(this->m_image, this->m_buffer, NULL);
}
-void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
ImBuf *stackbuf = getImBuf();
@@ -170,7 +181,7 @@ void ImageAlphaOperation::executePixelSampled(float output[4], float x, float y,
}
}
-void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_depthBuffer == NULL) {
output[0] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index 206f1509f60..75222559810 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -49,7 +49,9 @@ protected:
int m_imagewidth;
int m_framenumber;
int m_numberOfChannels;
-
+ const RenderData *m_rd;
+ const char *m_viewName;
+
BaseImageOperation();
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -64,7 +66,8 @@ public:
void deinitExecution();
void setImage(Image *image) { this->m_image = image; }
void setImageUser(ImageUser *imageuser) { this->m_imageUser = imageuser; }
-
+ void setRenderData(const RenderData *rd) { this->m_rd = rd; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setFramenumber(int framenumber) { this->m_framenumber = framenumber; }
};
class ImageOperation : public BaseImageOperation {
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cpp
index 18611c051d3..43b7b30319d 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cpp
@@ -241,7 +241,7 @@ void *InpaintSimpleOperation::initializeTileData(rcti *rect)
return this->m_cached_buffer;
}
-void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void *data)
+void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
this->clamp_xy(x, y);
copy_v4_v4(output, this->get_pixel(x, y));
@@ -268,7 +268,7 @@ void InpaintSimpleOperation::deinitExecution()
this->m_cached_buffer_ready = false;
}
-bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cached_buffer_ready) {
return false;
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
index 1633d2a2f1d..dd87578ea78 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
@@ -267,7 +267,7 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect)
return tile_data;
}
-void KeyingScreenOperation::deinitializeTileData(rcti *rect, void *data)
+void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
TileData *tile_data = (TileData *) data;
@@ -278,7 +278,7 @@ void KeyingScreenOperation::deinitializeTileData(rcti *rect, void *data)
MEM_freeN(tile_data);
}
-void KeyingScreenOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void KeyingScreenOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
index 0e48d5963c6..50ac3b5e055 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
@@ -52,7 +52,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], float x, floa
this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
/* one line thread-friend algorithm:
- * output[0] = max(inputValue[3], min(high, max(low, ((inColor[0]-low)/(high-low))))
+ * output[0] = max(inputValue[3], min(high, max(low, ((inColor[0] - low) / (high - low))));
*/
/* test range */
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index bb8fe825c68..ffa48ce3956 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -41,7 +41,7 @@ void MapUVOperation::initExecution()
this->m_inputUVProgram = this->getInputSocketReader(1);
}
-void MapUVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MapUVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float xy[2] = { x, y };
float uv[2], deriv[2][2], alpha;
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 8c8ba93327d..220b4e908a6 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -1,4 +1,5 @@
/*
+
* Copyright 2012, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
@@ -127,7 +128,7 @@ void MaskOperation::determineResolution(unsigned int resolution[2], unsigned int
}
}
-void MaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
const float xy[2] = {
(x * this->m_maskWidthInv) + this->m_mask_px_ofs[0],
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 447ca1bb4f6..040a0315d69 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -33,7 +33,9 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
this->m_attribute = MCA_X;
}
-void MovieClipAttributeOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MovieClipAttributeOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
if (!this->m_valueSet) {
float loc[2], scale, angle;
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
index 133b6d520eb..1e4821f0cd3 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
@@ -71,7 +71,7 @@ void MovieClipBaseOperation::deinitExecution()
}
}
-void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index 50fabb09dbb..4f34d7fb150 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -121,7 +121,7 @@ void MovieDistortionOperation::deinitExecution()
}
-void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_cache != NULL) {
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
index 23fba5a7999..00be3b1cdde 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
@@ -27,18 +27,27 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
-MultilayerBaseOperation::MultilayerBaseOperation(int passindex) : BaseImageOperation()
+MultilayerBaseOperation::MultilayerBaseOperation(int passtype, int view) : BaseImageOperation()
{
- this->m_passId = passindex;
+ this->m_passtype = passtype;
+ this->m_view = view;
}
+
ImBuf *MultilayerBaseOperation::getImBuf()
{
- RenderPass *rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId);
- if (rpass) {
- this->m_imageUser->pass = m_passId;
- BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser);
- return BaseImageOperation::getImBuf();
+ /* temporarily changes the view to get the right ImBuf */
+ int view = this->m_imageUser->view;
+
+ this->m_imageUser->view = this->m_view;
+ this->m_imageUser->passtype = this->m_passtype;
+
+ if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) {
+ ImBuf *ibuf = BaseImageOperation::getImBuf();
+ this->m_imageUser->view = view;
+ return ibuf;
}
+
+ this->m_imageUser->view = view;
return NULL;
}
@@ -74,7 +83,7 @@ void MultilayerColorOperation::executePixelSampled(float output[4], float x, flo
}
}
-void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_imageFloatBuffer == NULL) {
output[0] = 0.0f;
@@ -91,7 +100,7 @@ void MultilayerValueOperation::executePixelSampled(float output[4], float x, flo
}
}
-void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_imageFloatBuffer == NULL) {
output[0] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index 37bee1b6a8c..2e140577d74 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -29,7 +29,8 @@
class MultilayerBaseOperation : public BaseImageOperation {
private:
- int m_passId;
+ int m_passtype;
+ int m_view;
RenderLayer *m_renderlayer;
protected:
ImBuf *getImBuf();
@@ -37,13 +38,13 @@ public:
/**
* Constructor
*/
- MultilayerBaseOperation(int passindex);
+ MultilayerBaseOperation(int passtype, int view);
void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; }
};
class MultilayerColorOperation : public MultilayerBaseOperation {
public:
- MultilayerColorOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerColorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_COLOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@@ -51,7 +52,7 @@ public:
class MultilayerValueOperation : public MultilayerBaseOperation {
public:
- MultilayerValueOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerValueOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VALUE);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@@ -59,7 +60,7 @@ public:
class MultilayerVectorOperation : public MultilayerBaseOperation {
public:
- MultilayerVectorOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerVectorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VECTOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
index e0b5893ffbb..504470f1a7e 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
@@ -60,7 +60,7 @@ void NormalizeOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool NormalizeOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_cachedInstance) return false;
@@ -118,7 +118,7 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-void NormalizeOperation::deinitializeTileData(rcti *rect, void *data)
+void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
new file mode 100644
index 00000000000..7786359c06a
--- /dev/null
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * 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:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ * Lukas Tönne
+ * Dalai Felinto
+ */
+
+#include "COM_OutputFileOperation.h"
+#include "COM_OutputFileMultiViewOperation.h"
+
+#include <string.h>
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "DNA_color_types.h"
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
+}
+
+/************************************ OpenEXR Singlelayer Multiview *****************************************/
+
+OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation(
+ const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
+ : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
+{
+}
+
+void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename)
+{
+ size_t width = this->getWidth();
+ size_t height = this->getHeight();
+ SceneRenderView *srv;
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
+ continue;
+
+ IMB_exr_add_view(exrhandle, srv->name);
+ add_exr_channels(exrhandle, NULL, this->m_datatype, srv->name, width, false, NULL);
+ }
+
+ BLI_make_existing_file(filename);
+
+ /* prepare the file with all the channels */
+
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_format->exr_codec, NULL) == 0) {
+ printf("Error Writing Singlelayer Multiview Openexr\n");
+ IMB_exr_close(exrhandle);
+ }
+ else {
+ IMB_exr_clear_channels(exrhandle);
+ return exrhandle;
+ }
+ }
+ return NULL;
+}
+
+void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+
+ BKE_image_path_from_imtype(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ exrhandle = this->get_handle(filename);
+ add_exr_channels(exrhandle, NULL, this->m_datatype, this->m_viewName, width,
+ this->m_format->depth == R_IMF_CHAN_DEPTH_16, this->m_outputBuffer);
+
+ /* memory can only be freed after we write all views to the file */
+ this->m_outputBuffer = NULL;
+ this->m_imageInput = NULL;
+
+ /* ready to close the file */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ IMB_exr_write_channels(exrhandle);
+
+ /* free buffer memory for all the views */
+ free_exr_channels(exrhandle, this->m_rd, NULL, this->m_datatype);
+
+ /* remove exr handle and data */
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
+
+/************************************ OpenEXR Multilayer Multiview *****************************************/
+
+OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation(
+ const RenderData *rd, const bNodeTree *tree, const char *path,
+ char exr_codec, bool exr_half_float, const char *viewName)
+ : OutputOpenExrMultiLayerOperation(rd, tree, path, exr_codec, exr_half_float, viewName)
+{
+}
+
+void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename)
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+
+ void *exrhandle;
+ SceneRenderView *srv;
+
+ /* get a new global handle */
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ /* check renderdata for amount of views */
+ for (srv = (SceneRenderView *) this->m_rd->views.first; srv; srv = srv->next) {
+
+ if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
+ continue;
+
+ IMB_exr_add_view(exrhandle, srv->name);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i)
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype,
+ srv->name, width, this->m_exr_half_float, NULL);
+ }
+
+ BLI_make_existing_file(filename);
+
+ /* prepare the file with all the channels for the header */
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, NULL) == 0) {
+ printf("Error Writing Multilayer Multiview Openexr\n");
+ IMB_exr_close(exrhandle);
+ }
+ else {
+ IMB_exr_clear_channels(exrhandle);
+ return exrhandle;
+ }
+ }
+ return NULL;
+}
+
+void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+
+ BKE_image_path_from_imtype(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ exrhandle = this->get_handle(filename);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i)
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, this->m_viewName,
+ width, this->m_exr_half_float, this->m_layers[i].outputBuffer);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ /* memory can only be freed after we write all views to the file */
+ this->m_layers[i].outputBuffer = NULL;
+ this->m_layers[i].imageInput = NULL;
+ }
+
+ /* ready to close the file */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ IMB_exr_write_channels(exrhandle);
+
+ /* free buffer memory for all the views */
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ free_exr_channels(exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
+ }
+
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
+
+
+/******************************** Stereo3D ******************************/
+
+OutputStereoOperation::OutputStereoOperation(
+ const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+ const char *name, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
+ : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
+{
+ BLI_strncpy(this->m_name, name, sizeof(this->m_name));
+ this->m_channels = get_datatype_size(datatype);
+}
+
+void *OutputStereoOperation::get_handle(const char *filename)
+{
+ size_t width = this->getWidth();
+ size_t height = this->getHeight();
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ size_t i;
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ for (i = 0; i < 2; i++)
+ IMB_exr_add_view(exrhandle, names[i]);
+
+ return exrhandle;
+ }
+ return NULL;
+}
+
+void OutputStereoOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = this->get_handle(this->m_path);
+ float *buf = this->m_outputBuffer;
+
+ /* populate single EXR channel with view data */
+ IMB_exr_add_channel(exrhandle, NULL, this->m_name, this->m_viewName, 1, this->m_channels * width * height, buf,
+ this->m_format->depth == R_IMF_CHAN_DEPTH_16);
+
+ this->m_imageInput = NULL;
+ this->m_outputBuffer = NULL;
+
+ /* create stereo ibuf */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ ImBuf *ibuf[3] = {NULL};
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+ int i;
+
+ /* get rectf from EXR */
+ for (i = 0; i < 2; i++) {
+ float *rectf = IMB_exr_channel_rect(exrhandle, NULL, this->m_name, names[i]);
+ ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0);
+
+ ibuf[i]->channels = this->m_channels;
+ ibuf[i]->rect_float = rectf;
+ ibuf[i]->mall |= IB_rectfloat;
+ ibuf[i]->dither = this->m_rd->dither_intensity;
+
+ /* do colormanagement in the individual views, so it doesn't need to do in the stereo */
+ IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, this->m_viewSettings,
+ this->m_displaySettings, this->m_format);
+ IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
+ }
+
+ /* create stereo buffer */
+ ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]);
+
+ BKE_image_path_from_imformat(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ BKE_imbuf_write(ibuf[2], filename, this->m_format);
+
+ /* imbuf knows which rects are not part of ibuf */
+ for (i = 0; i < 3; i++)
+ IMB_freeImBuf(ibuf[i]);
+
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
new file mode 100644
index 00000000000..0e3cde66897
--- /dev/null
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * 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:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ * Lukas Tönne
+ * Dalai Felinto
+ */
+
+#ifndef _COM_OutputFileMultiViewOperation_h
+#define _COM_OutputFileMultiViewOperation_h
+#include "COM_NodeOperation.h"
+
+#include "BLI_rect.h"
+#include "BLI_path_util.h"
+
+#include "DNA_color_types.h"
+#include "DNA_userdef_types.h"
+
+#include "intern/openexr/openexr_multi.h"
+
+class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation {
+private:
+public:
+ OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
+ ImageFormatData *format, const char *path,
+ const ColorManagedViewSettings *viewSettings,
+ const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
+
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+/* Writes inputs into OpenEXR multilayer channels. */
+class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation {
+private:
+public:
+ OutputOpenExrMultiLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, const char *path,
+ char exr_codec, bool exr_half_float, const char *viewName);
+
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+/**/
+class OutputStereoOperation : public OutputSingleLayerOperation {
+private:
+ char m_name[FILE_MAX];
+ size_t m_channels;
+public:
+ OutputStereoOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
+ struct ImageFormatData *format, const char *path, const char *name,
+ const ColorManagedViewSettings *viewSettings,
+ const ColorManagedDisplaySettings *displaySettings, const char *viewName);
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+#endif
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 2f92351c00d..fdf5a0b48cf 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -29,6 +29,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "DNA_color_types.h"
@@ -39,7 +40,61 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
-static int get_datatype_size(DataType datatype)
+void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype,
+ const char *viewName, const size_t width, bool use_half_float, float *buf)
+{
+ /* create channels */
+ switch (datatype) {
+ case COM_DT_VALUE:
+ IMB_exr_add_channel(exrhandle, layerName, "V", viewName, 1, width, buf ? buf : NULL, use_half_float);
+ break;
+ case COM_DT_VECTOR:
+ IMB_exr_add_channel(exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : NULL, use_half_float);
+ IMB_exr_add_channel(exrhandle, layerName, "Y", viewName, 3, 3 * width, buf ? buf + 1 : NULL, use_half_float);
+ IMB_exr_add_channel(exrhandle, layerName, "Z", viewName, 3, 3 * width, buf ? buf + 2 : NULL, use_half_float);
+ break;
+ case COM_DT_COLOR:
+ IMB_exr_add_channel(exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : NULL, use_half_float);
+ IMB_exr_add_channel(exrhandle, layerName, "G", viewName, 4, 4 * width, buf ? buf + 1 : NULL, use_half_float);
+ IMB_exr_add_channel(exrhandle, layerName, "B", viewName, 4, 4 * width, buf ? buf + 2 : NULL, use_half_float);
+ IMB_exr_add_channel(exrhandle, layerName, "A", viewName, 4, 4 * width, buf ? buf + 3 : NULL, use_half_float);
+ break;
+ default:
+ break;
+ }
+}
+
+void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype)
+{
+ SceneRenderView *srv;
+
+ /* check renderdata for amount of views */
+ for (srv = (SceneRenderView *) rd->views.first; srv; srv = srv->next) {
+ float *rect = NULL;
+
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+
+ /* the pointer is stored in the first channel of each datatype */
+ switch (datatype) {
+ case COM_DT_VALUE:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "V", srv->name);
+ break;
+ case COM_DT_VECTOR:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "X", srv->name);
+ break;
+ case COM_DT_COLOR:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "R", srv->name);
+ break;
+ default:
+ break;
+ }
+ if (rect)
+ MEM_freeN(rect);
+ }
+}
+
+int get_datatype_size(DataType datatype)
{
switch (datatype) {
case COM_DT_VALUE: return 1;
@@ -94,7 +149,7 @@ static void write_buffer_rect(rcti *rect, const bNodeTree *tree,
OutputSingleLayerOperation::OutputSingleLayerOperation(
const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
@@ -110,6 +165,7 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
this->m_viewSettings = viewSettings;
this->m_displaySettings = displaySettings;
+ this->m_viewName = viewName;
}
void OutputSingleLayerOperation::initExecution()
@@ -118,7 +174,7 @@ void OutputSingleLayerOperation::initExecution()
this->m_outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_datatype);
}
-void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
write_buffer_rect(rect, this->m_tree, this->m_imageInput, this->m_outputBuffer, this->getWidth(), this->m_datatype);
}
@@ -131,6 +187,7 @@ void OutputSingleLayerOperation::deinitExecution()
ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0);
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
+ const char *suffix;
ibuf->channels = size;
ibuf->rect_float = this->m_outputBuffer;
@@ -140,10 +197,12 @@ void OutputSingleLayerOperation::deinitExecution()
IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings,
this->m_format);
+ suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
+
BKE_image_path_from_imformat(
- filename, this->m_path, bmain->name, this->m_rd->cfra,
- this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true);
-
+ filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
+
if (0 == BKE_imbuf_write(ibuf, filename, this->m_format))
printf("Cannot save Node File Output to %s\n", filename);
else
@@ -155,6 +214,7 @@ void OutputSingleLayerOperation::deinitExecution()
this->m_imageInput = NULL;
}
+/******************************* MultiLayer *******************************/
OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_)
{
@@ -168,13 +228,16 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo
}
OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(
- const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec)
+ const RenderData *rd, const bNodeTree *tree, const char *path,
+ char exr_codec, bool exr_half_float, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
BLI_strncpy(this->m_path, path, sizeof(this->m_path));
this->m_exr_codec = exr_codec;
+ this->m_exr_half_float = exr_half_float;
+ this->m_viewName = viewName;
}
void OutputOpenExrMultiLayerOperation::add_layer(const char *name, DataType datatype, bool use_layer)
@@ -194,7 +257,7 @@ void OutputOpenExrMultiLayerOperation::initExecution()
}
}
-void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
OutputOpenExrLayer &layer = this->m_layers[i];
@@ -210,56 +273,26 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
if (width != 0 && height != 0) {
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
+ const char *suffix;
void *exrhandle = IMB_exr_get_handle();
-
+
+ suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
BKE_image_path_from_imtype(
filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
- (this->m_rd->scemode & R_EXTENSION) != 0, true);
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
BLI_make_existing_file(filename);
-
+
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (!layer.imageInput)
continue; /* skip unconnected sockets */
- char channelname[EXR_TOT_MAXNAME];
- BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2);
- char *channelname_ext = channelname + strlen(channelname);
-
- float *buf = this->m_layers[i].outputBuffer;
-
- /* create channels */
- switch (this->m_layers[i].datatype) {
- case COM_DT_VALUE:
- strcpy(channelname_ext, ".V");
- IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf);
- break;
- case COM_DT_VECTOR:
- strcpy(channelname_ext, ".X");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf);
- strcpy(channelname_ext, ".Y");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1);
- strcpy(channelname_ext, ".Z");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2);
- break;
- case COM_DT_COLOR:
- strcpy(channelname_ext, ".R");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf);
- strcpy(channelname_ext, ".G");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1);
- strcpy(channelname_ext, ".B");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2);
- strcpy(channelname_ext, ".A");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3);
- break;
- default:
- break;
- }
-
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, "", width,
+ this->m_exr_half_float, this->m_layers[i].outputBuffer);
}
/* when the filename has no permissions, this can fail */
- if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec)) {
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, NULL)) {
IMB_exr_write_channels(exrhandle);
}
else {
@@ -279,3 +312,4 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
}
}
+
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 03278c5b149..93468977a66 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -34,7 +34,7 @@
/* Writes the image to a single-layer file. */
class OutputSingleLayerOperation : public NodeOperation {
-private:
+protected:
const RenderData *m_rd;
const bNodeTree *m_tree;
@@ -47,12 +47,14 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
+
+ const char *m_viewName;
public:
OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName);
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { return true; }
+ bool isOutputOperation(bool /*rendering*/) const { return true; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_LOW; }
@@ -75,7 +77,7 @@ struct OutputOpenExrLayer {
/* Writes inputs into OpenEXR multilayer channels. */
class OutputOpenExrMultiLayerOperation : public NodeOperation {
-private:
+protected:
typedef std::vector<OutputOpenExrLayer> LayerList;
const RenderData *m_rd;
@@ -83,15 +85,18 @@ private:
char m_path[FILE_MAX];
char m_exr_codec;
+ bool m_exr_half_float;
LayerList m_layers;
+ const char *m_viewName;
public:
- OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec);
+ OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path,
+ char exr_codec, bool exr_half_float, const char *viewName);
void add_layer(const char *name, DataType datatype, bool use_layer);
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { return true; }
+ bool isOutputOperation(bool /*rendering*/) const { return true; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_LOW; }
@@ -99,4 +104,9 @@ public:
bool isFileOutputOperation() const { return true; }
};
+void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName,
+ const size_t width, bool use_half_float, float *buf);
+void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype);
+int get_datatype_size(DataType datatype);
+
#endif
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index 8133f392ac6..d7d1c9c0c93 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -100,7 +100,7 @@ void PlaneDistortWarpImageOperation::deinitExecution()
this->m_pixelReader = NULL;
}
-void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float uv[2];
float deriv[2][2];
@@ -194,7 +194,7 @@ void PlaneDistortMaskOperation::initExecution()
BLI_jitter_init(m_jitter, m_osa);
}
-void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float point[2];
int inside_counter = 0;
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index 03205130a74..a56aa0cbaa6 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -71,7 +71,7 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
}
}
-void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp
index 69290cd7c3c..aa667884de6 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cpp
@@ -85,7 +85,7 @@ void PreviewOperation::deinitExecution()
this->m_input = NULL;
}
-void PreviewOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
int offset;
float color[4];
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.h b/source/blender/compositor/operations/COM_PreviewOperation.h
index 3e97acec7bb..5da7a25ac5d 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.h
+++ b/source/blender/compositor/operations/COM_PreviewOperation.h
@@ -45,7 +45,7 @@ public:
PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
void verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key);
- bool isOutputOperation(bool rendering) const { return !G.background; }
+ bool isOutputOperation(bool /*rendering*/) const { return !G.background; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const;
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
index 7f6079c55aa..02d1809efbb 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
@@ -40,7 +40,7 @@ void ProjectorLensDistortionOperation::initExecution()
this->m_inputProgram = this->getInputSocketReader(0);
}
-void *ProjectorLensDistortionOperation::initializeTileData(rcti *rect)
+void *ProjectorLensDistortionOperation::initializeTileData(rcti * /*rect*/)
{
updateDispersion();
void *buffer = this->m_inputProgram->initializeTileData(NULL);
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
index ad4084a7092..bf0f24e06be 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
@@ -32,7 +32,7 @@ ReadBufferOperation::ReadBufferOperation(DataType datatype) : NodeOperation()
this->m_buffer = NULL;
}
-void *ReadBufferOperation::initializeTileData(rcti *rect)
+void *ReadBufferOperation::initializeTileData(rcti * /*rect*/)
{
return m_buffer;
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 409fa68bacf..af176a766ff 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -23,6 +23,7 @@
#include "COM_RenderLayersProg.h"
#include "BLI_listbase.h"
+#include "BKE_scene.h"
#include "DNA_scene_types.h"
extern "C" {
@@ -57,11 +58,10 @@ void RenderLayersBaseProg::initExecution()
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
- if (rl && rl->rectf) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass);
-
+ 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 = rl->rectf;
+ this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName);
}
}
}
@@ -179,7 +179,7 @@ void RenderLayersBaseProg::deinitExecution()
this->m_inputBuffer = NULL;
}
-void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
Scene *sce = this->getScene();
Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL;
@@ -195,7 +195,7 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig
SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId());
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
- if (rl && rl->rectf) {
+ if (rl) {
resolution[0] = rl->rectx;
resolution[1] = rl->recty;
}
@@ -269,7 +269,7 @@ RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z
this->addOutputSocket(COM_DT_VALUE);
}
-void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int ix = x;
int iy = y;
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index f73d9de3e27..2ddbc968c01 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -51,7 +51,12 @@ private:
* layerId of the layer where this operation needs to get its data from
*/
short m_layerId;
-
+
+ /**
+ * viewName of the view to use (unless another view is specified by the node
+ */
+ const char *m_viewName;
+
/**
* cached instance to the float buffer inside the layer
*/
@@ -97,6 +102,8 @@ public:
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
void setLayerId(short layerId) { this->m_layerId = layerId; }
short getLayerId() { return this->m_layerId; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
+ const char *getViewName() { return this->m_viewName; }
void initExecution();
void deinitExecution();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp
index 23e8ce86fd9..117ae743ee7 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp
@@ -279,7 +279,7 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
-void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
unsigned int nr[2];
nr[0] = this->m_newWidth;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index ad9b761da45..acd76fa79a8 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -70,7 +70,7 @@ void ScreenLensDistortionOperation::initExecution()
}
}
-void *ScreenLensDistortionOperation::initializeTileData(rcti *rect)
+void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
@@ -208,7 +208,7 @@ void ScreenLensDistortionOperation::determineUV(float result[6], float x, float
get_delta(uv_dot, m_k4[2], uv, result + 4);
}
-bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInputValue;
newInputValue.xmin = 0;
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cpp
index 94a863e628b..1a362bc55e2 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cpp
@@ -27,7 +27,9 @@ SetColorOperation::SetColorOperation() : NodeOperation()
this->addOutputSocket(COM_DT_COLOR);
}
-void SetColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetColorOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
copy_v4_v4(output, this->m_color);
}
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
index be72ffd0336..7057ecb14c1 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
@@ -37,7 +37,7 @@ void SetSamplerOperation::deinitExecution()
this->m_reader = NULL;
}
-void SetSamplerOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetSamplerOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
this->m_reader->readSampled(output, x, y, this->m_sampler);
}
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cpp
index 51e09a63051..b6cfb760a98 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cpp
@@ -27,7 +27,9 @@ SetValueOperation::SetValueOperation() : NodeOperation()
this->addOutputSocket(COM_DT_VALUE);
}
-void SetValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetValueOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_value;
}
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
index 769eaf1d2ed..1b0327683a9 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
@@ -28,7 +28,9 @@ SetVectorOperation::SetVectorOperation() : NodeOperation()
this->addOutputSocket(COM_DT_VECTOR);
}
-void SetVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetVectorOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_x;
output[1] = this->m_y;
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp
index 367c7eefa25..cd2166591bc 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cpp
@@ -56,7 +56,7 @@ void SplitOperation::deinitExecution()
this->m_image2Input = NULL;
}
-void SplitOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SplitOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int perc = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f : this->m_splitPercentage * this->getHeight() / 100.0f;
bool image1 = this->m_xSplit ? x > perc : y > perc;
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
index 0ca687ea162..a681583809c 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -293,7 +293,7 @@ static void accumulate_line(MemoryBuffer *input, float output[4], const float co
}
}
-void *SunBeamsOperation::initializeTileData(rcti *rect)
+void *SunBeamsOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = getInputOperation(0)->initializeTileData(NULL);
return buffer;
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 1b0485afb8d..2ff6cc047c6 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -117,7 +117,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
}
}
-MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti *rect2)
+MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti * /*rect2*/)
{
int height = getHeight();
int width = getWidth();
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp
index e8a578fa131..c581d115a2f 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp
@@ -24,6 +24,10 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
TonemapOperation::TonemapOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
@@ -69,7 +73,7 @@ void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y,
this->m_imageReader->read(output, x, y, NULL);
- const float L = rgb_to_luma_y(output);
+ const float L = IMB_colormanagement_get_luminance(output);
float I_l = output[0] + ic * (L - output[0]);
float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
float I_a = I_l + ia * (I_g - I_l);
@@ -93,7 +97,7 @@ void TonemapOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool TonemapOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool TonemapOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
@@ -125,7 +129,7 @@ void *TonemapOperation::initializeTileData(rcti *rect)
float Lav = 0.f;
float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
while (p--) {
- float L = rgb_to_luma_y(bc);
+ float L = IMB_colormanagement_get_luminance(bc);
Lav += L;
add_v3_v3(cav, bc);
lsum += logf(MAX2(L, 0.0f) + 1e-5f);
@@ -146,7 +150,7 @@ void *TonemapOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-void TonemapOperation::deinitializeTileData(rcti *rect, void *data)
+void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
index a76e0866d0d..ca169d03fbc 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
@@ -102,7 +102,9 @@ void TrackPositionOperation::initExecution()
}
}
-void TrackPositionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void TrackPositionOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis];
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cpp
index 191388a42fb..fcf99a10a73 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cpp
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cpp
@@ -52,7 +52,7 @@ void TranslateOperation::deinitExecution()
}
-void TranslateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void TranslateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
ensureDelta();
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 6e4caeef613..1ec52571be8 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -62,8 +62,7 @@ void VariableSizeBokehBlurOperation::initExecution()
#endif
QualityStepHelper::initExecution(COM_QH_INCREASE);
}
-struct VariableSizeBokehBlurTileData
-{
+struct VariableSizeBokehBlurTileData {
MemoryBuffer *color;
MemoryBuffer *bokeh;
MemoryBuffer *size;
@@ -89,7 +88,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
return data;
}
-void VariableSizeBokehBlurOperation::deinitializeTileData(rcti *rect, void *data)
+void VariableSizeBokehBlurOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data;
delete result;
@@ -187,7 +186,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", NULL);
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
index 8dc06ef07d7..36f06e92436 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
@@ -91,7 +91,7 @@ void *VectorBlurOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-bool VectorBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool VectorBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cachedInstance == NULL) {
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index 53c0acd781a..aa47d3427d0 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -23,6 +23,7 @@
#include "COM_ViewerOperation.h"
#include "BLI_listbase.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
#include "PIL_time.h"
@@ -57,6 +58,8 @@ ViewerOperation::ViewerOperation() : NodeOperation()
this->m_imageInput = NULL;
this->m_alphaInput = NULL;
this->m_depthInput = NULL;
+ this->m_rd = NULL;
+ this->m_viewName = NULL;
}
void ViewerOperation::initExecution()
@@ -80,7 +83,7 @@ void ViewerOperation::deinitExecution()
this->m_outputBuffer = NULL;
}
-void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
float *buffer = this->m_outputBuffer;
float *depthbuffer = this->m_depthBuffer;
@@ -123,11 +126,25 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
void ViewerOperation::initImage()
{
Image *ima = this->m_image;
+ ImageUser iuser = *this->m_imageUser;
void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, this->m_imageUser, &lock);
+ ImBuf *ibuf;
+
+ /* make sure the image has the correct number of views */
+ if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
+ BKE_image_verify_viewer_views(this->m_rd, ima, this->m_imageUser);
+ }
- if (!ibuf) return;
BLI_lock_thread(LOCK_DRAW_IMAGE);
+
+ /* local changes to the original ImageUser */
+ iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
+
+ if (!ibuf) {
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+ return;
+ }
if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) {
imb_freerectImBuf(ibuf);
@@ -146,7 +163,6 @@ void ViewerOperation::initImage()
if (m_doDepthBuffer) {
addzbuffloatImBuf(ibuf);
}
- BLI_unlock_thread(LOCK_DRAW_IMAGE);
/* now we combine the input with ibuf */
this->m_outputBuffer = ibuf->rect_float;
@@ -159,6 +175,8 @@ void ViewerOperation::initImage()
}
BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock);
+
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
}
void ViewerOperation::updateImage(rcti *rect)
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h
index dcc7ffa3730..107aee3a82f 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -40,7 +40,9 @@ private:
bool m_doDepthBuffer;
ImBuf *m_ibuf;
bool m_useAlphaInput;
-
+ const RenderData *m_rd;
+ const char *m_viewName;
+
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
@@ -53,7 +55,7 @@ public:
void initExecution();
void deinitExecution();
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { if (G.background) return false; return isActiveViewerOutput(); }
+ bool isOutputOperation(bool /*rendering*/) const { if (G.background) return false; return isActiveViewerOutput(); }
void setImage(Image *image) { this->m_image = image; }
void setImageUser(ImageUser *imageUser) { this->m_imageUser = imageUser; }
const bool isActiveViewerOutput() const { return this->m_active; }
@@ -67,6 +69,8 @@ public:
const CompositorPriority getRenderPriority() const;
bool isViewerOperation() const { return true; }
void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; }
+ void setRenderData(const RenderData *rd) { this->m_rd = rd; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; }
void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; }
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
index fccff2a33bf..b3c1c00804e 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
@@ -57,7 +57,7 @@ void WriteBufferOperation::deinitExecution()
this->m_memoryProxy->free();
}
-void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer();
float *buffer = memoryBuffer->getBuffer();
@@ -110,7 +110,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
memoryBuffer->setCreatedState();
}
-void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti *rect, unsigned int chunkNumber,
+void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti * /*rect*/, unsigned int /*chunkNumber*/,
MemoryBuffer **inputMemoryBuffers, MemoryBuffer *outputBuffer)
{
float *outputFloatBuffer = outputBuffer->getBuffer();
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
new file mode 100644
index 00000000000..dcdb14d0ba0
--- /dev/null
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -0,0 +1,118 @@
+# ***** 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.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Joshua Leung, Lukas Toenne
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ util
+ ../blenkernel
+ ../blenlib
+ ../bmesh
+ ../makesdna
+ ../makesrna
+ ../modifiers
+ ../windowmanager
+ ../../../intern/atomic
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ intern/depsgraph.cc
+ intern/depsnode.cc
+ intern/depsnode_component.cc
+ intern/depsnode_operation.cc
+ intern/depsgraph_build.cc
+ intern/depsgraph_build_nodes.cc
+ intern/depsgraph_build_relations.cc
+ intern/depsgraph_debug.cc
+ intern/depsgraph_eval.cc
+ intern/depsgraph_query.cc
+ intern/depsgraph_queue.cc
+ intern/depsgraph_tag.cc
+ intern/depsgraph_type_defines.cc
+ util/depsgraph_util_cycle.cc
+ util/depsgraph_util_pchanmap.cc
+ util/depsgraph_util_transitive.cc
+
+ DEG_depsgraph.h
+ DEG_depsgraph_build.h
+ DEG_depsgraph_debug.h
+ DEG_depsgraph_query.h
+ intern/depsgraph.h
+ intern/depsnode.h
+ intern/depsnode_component.h
+ intern/depsnode_operation.h
+ intern/depsnode_opcodes.h
+ intern/depsgraph_build.h
+ intern/depsgraph_debug.h
+ intern/depsgraph_intern.h
+ intern/depsgraph_queue.h
+ intern/depsgraph_types.h
+
+ util/depsgraph_util_cycle.h
+ util/depsgraph_util_function.h
+ util/depsgraph_util_hash.h
+ util/depsgraph_util_map.h
+ util/depsgraph_util_pchanmap.h
+ util/depsgraph_util_set.h
+ util/depsgraph_util_transitive.h
+)
+
+TEST_UNORDERED_MAP_SUPPORT()
+if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_TR1_UNORDERED_MAP)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+endif()
+
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
+if(WITH_BOOST)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ )
+ add_definitions(-DHAVE_BOOST_FUNCTION_BINDINGS)
+endif()
+
+blender_add_lib(bf_depsgraph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
new file mode 100644
index 00000000000..b91f99ecd20
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -0,0 +1,215 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph.h
+ * \ingroup depsgraph
+ *
+ * Public API for Depsgraph
+ *
+ * Dependency Graph
+ * ================
+ *
+ * The dependency graph tracks relations between various pieces of data in
+ * a Blender file, but mainly just those which make up scene data. It is used
+ * to determine the set of operations need to ensure that all data has been
+ * correctly evaluated in response to changes, based on dependencies and visibility
+ * of affected data.
+ *
+ *
+ * Evaluation Engine
+ * =================
+ *
+ * The evaluation takes the operation-nodes the Depsgraph has tagged for updating,
+ * and schedules them up for being evaluated/executed such that the all dependency
+ * relationship constraints are satisfied.
+ */
+
+/* ************************************************* */
+/* Forward-defined typedefs for core types
+ * - These are used in all depsgraph code and by all callers of Depsgraph API...
+ */
+
+#ifndef __DEG_DEPSGRAPH_H__
+#define __DEG_DEPSGRAPH_H__
+
+/* Dependency Graph */
+typedef struct Depsgraph Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct EvaluationContext;
+struct Main;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool DEG_depsgraph_use_legacy(void);
+void DEG_depsgraph_switch_to_legacy(void);
+void DEG_depsgraph_switch_to_new(void);
+
+/* ************************************************ */
+/* Depsgraph API */
+
+/* CRUD ------------------------------------------- */
+
+// Get main depsgraph instance from context!
+
+/* Create new Depsgraph instance */
+// TODO: what args are needed here? What's the building-graph entry point?
+Depsgraph *DEG_graph_new(void);
+
+/* Free Depsgraph itself and all its data */
+void DEG_graph_free(Depsgraph *graph);
+
+/* Node Types Registry ---------------------------- */
+
+/* Register all node types */
+void DEG_register_node_types(void);
+
+/* Free node type registry on exit */
+void DEG_free_node_types(void);
+
+/* Update Tagging -------------------------------- */
+
+/* Tag node(s) associated with states such as time and visibility */
+void DEG_scene_update_flags(Depsgraph *graph, const bool do_time);
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(struct Main *bmain, struct Scene *scene);
+
+/* Update all dependency graphs when visible scenes/layers changes. */
+void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+
+/* Tag node(s) associated with changed data for later updates */
+void DEG_graph_id_tag_update(struct Main *bmain,
+ Depsgraph *graph,
+ struct ID *id);
+void DEG_graph_data_tag_update(Depsgraph *graph, const struct PointerRNA *ptr);
+void DEG_graph_property_tag_update(Depsgraph *graph, const struct PointerRNA *ptr, const struct PropertyRNA *prop);
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(struct ID *id, short flag);
+void DEG_id_tag_update_ex(struct Main *bmain,
+ struct ID *id,
+ short flag);
+
+/* Tag given ID type for update.
+ *
+ * Used by all sort of render engines to quickly check if
+ * IDs of a given type need to be checked for update.
+ */
+void DEG_id_type_tag(struct Main *bmain, short idtype);
+
+void DEG_ids_clear_recalc(struct Main *bmain);
+
+/* Update Flushing ------------------------------- */
+
+/* Flush updates */
+void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
+
+/* Flush updates for all IDs */
+void DEG_ids_flush_tagged(struct Main *bmain);
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(struct Main *bmain,
+ struct Scene *scene,
+ bool time);
+
+/* Clear all update tags
+ * - For aborted updates, or after successful evaluation
+ */
+void DEG_graph_clear_tags(Depsgraph *graph);
+
+/* ************************************************ */
+/* Evaluation Engine API */
+
+/* Evaluation Context ---------------------------- */
+
+/* Create new evaluation context. */
+struct EvaluationContext *DEG_evaluation_context_new(int mode);
+
+/* Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, int mode);
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
+
+/* Graph Evaluation ----------------------------- */
+
+/* Frame changed recalculation entry point
+ * < context_type: context to perform evaluation for
+ * < ctime: (frame) new frame to evaluate values on
+ */
+void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
+ struct Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layer);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ * < layers: visible layers bitmask to update the graph for
+ */
+void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ */
+void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ struct Scene *scene);
+
+/* Editors Integration -------------------------- */
+
+/* Mechanism to allow editors to be informed of depsgraph updates,
+ * to do their own updates based on changes.
+ */
+
+typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
+typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
+ struct Scene *scene,
+ int updated);
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
new file mode 100644
index 00000000000..f680c47247a
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -0,0 +1,121 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_build.h
+ * \ingroup depsgraph
+ *
+ * Public API for Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_BUILD_H__
+#define __DEG_DEPSGRAPH_BUILD_H__
+
+/* ************************************************* */
+
+/* Dependency Graph */
+struct Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct Main;
+struct Scene;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Graph Building -------------------------------- */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
+
+/* Tag relations from the given graph for update. */
+void DEG_graph_tag_relations_update(struct Depsgraph *graph);
+
+/* Tag all relations in the database for update.*/
+void DEG_relations_tag_update(struct Main *bmain);
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(struct Main *bmain,
+ struct Scene *scene);
+
+/* Delete scene graph. */
+void DEG_scene_graph_free(struct Scene *scene);
+
+/* Add Dependencies ----------------------------- */
+
+/* Handle for components to define their dependencies from callbacks.
+ * This is generated by the depsgraph and passed to dependency callbacks
+ * as a symbolic reference to the current DepsNode.
+ * All relations will be defined in reference to that node.
+ */
+struct DepsNodeHandle;
+
+struct Object;
+
+typedef enum eDepsSceneComponentType {
+ DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+} eDepsSceneComponentType;
+
+typedef enum eDepsObjectComponentType {
+ DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
+ DEG_OB_COMP_SHADING, /* Material Shading Component */
+} eDepsObjectComponentType;
+
+void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
+
+/* TODO(sergey): Remove once all geometry update is granular. */
+void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
+
+/* ************************************************ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
new file mode 100644
index 00000000000..374fad63c34
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -0,0 +1,111 @@
+/*
+ * ***** 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.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_debug.h
+ * \ingroup depsgraph
+ *
+ * Public API for Querying and Filtering Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_DEBUG_H__
+#define __DEG_DEPSGRAPH_DEBUG_H__
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DepsgraphSettings;
+struct GHash;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+/* ************************************************ */
+/* Statistics */
+
+typedef struct DepsgraphStatsTimes {
+ float duration_last;
+} DepsgraphStatsTimes;
+
+typedef struct DepsgraphStatsComponent {
+ struct DepsgraphStatsComponent *next, *prev;
+
+ char name[64];
+ DepsgraphStatsTimes times;
+} DepsgraphStatsComponent;
+
+typedef struct DepsgraphStatsID {
+ struct ID *id;
+
+ DepsgraphStatsTimes times;
+ ListBase components;
+} DepsgraphStatsID;
+
+typedef struct DepsgraphStats {
+ struct GHash *id_stats;
+} DepsgraphStats;
+
+struct DepsgraphStats *DEG_stats(void);
+
+void DEG_stats_verify(void);
+
+struct DepsgraphStatsID *DEG_stats_id(struct ID *id);
+
+/* ------------------------------------------------ */
+
+void DEG_stats_simple(const struct Depsgraph *graph,
+ size_t *r_outer,
+ size_t *r_operations,
+ size_t *r_relations);
+
+/* ************************************************ */
+/* Diagram-Based Graph Debugging */
+
+void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval);
+
+/* ************************************************ */
+
+/* Compare two dependency graphs. */
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2);
+
+/* Check that dependnecies in the graph are really up to date. */
+bool DEG_debug_scene_relations_validate(struct Main *bmain,
+ struct Scene *scene);
+
+
+/* Perform consistency check on the graph. */
+bool DEG_debug_consistency_check(struct Depsgraph *graph);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
new file mode 100644
index 00000000000..60d673d4c5b
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -0,0 +1,195 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_query.h
+ * \ingroup depsgraph
+ *
+ * Public API for Querying and Filtering Depsgraph.
+ */
+
+#ifndef __DEG_DEPSGRAPH_QUERY_H__
+#define __DEG_DEPSGRAPH_QUERY_H__
+
+struct ListBase;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ************************************************ */
+/* Type Defines */
+
+/* FilterPredicate Callback
+ *
+ * Defines a callback function which can be supplied to check whether a
+ * node is relevant or not.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to check
+ * < userdata: FilterPredicate state data (as needed)
+ * > returns: True if node is relevant
+ */
+typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
+
+
+/* Node Operation
+ *
+ * Performs some action on the given node, provided that the node was
+ * deemed to be relevant to operate on.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to perform operation on/with
+ * < userdata: Node Operation's state data (as needed)
+ * > returns: True if traversal should be aborted at this point
+ */
+typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
+
+/* ************************************************ */
+/* Low-Level Filtering API */
+
+/* Create a filtered copy of the given graph which contains only the
+ * nodes which fulfill the criteria specified using the FilterPredicate
+ * passed in.
+ *
+ * < graph: The graph to be copied and filtered
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, full graph is copied as-is)
+ * < userdata: State data for filter (as necessary)
+ *
+ * > returns: a full copy of all the relevant nodes - the matching subgraph
+ */
+// XXX: is there any need for extra settings/options for how the filtering goes?
+Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
+
+
+/* Traverse nodes in graph which are deemed relevant,
+ * performing the provided operation on the nodes.
+ *
+ * < graph: The graph to perform operations on
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, all nodes are considered valid targets)
+ * < filter_data: Custom state data for FilterPredicate
+ * (Note: This can be the same as op_data, where appropriate)
+ * < op: NodeOperation to perform on each node
+ * (If null, no graph traversal is performed for efficiency)
+ * < op_data: Custom state data for NodeOperation
+ * (Note: This can be the same as filter_data, where appropriate)
+ */
+void DEG_graph_traverse(const struct Depsgraph *graph,
+ DEG_FilterPredicate *filter, void *filter_data,
+ DEG_NodeOperation *op, void *op_data);
+
+/* ************************************************ */
+/* Node-Based Operations */
+// XXX: do we want to be able to attach conditional requirements here?
+
+/* Find an (outer) node matching given conditions
+ * ! Assumes that there will only be one such node, or that only the first one matters
+ *
+ * < graph: a dependency graph which may or may not contain a node matching these requirements
+ * < query: query conditions for the criteria that the node must satisfy
+ */
+//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
+
+/* Topology Queries (Direct) ---------------------- */
+
+/* Get list of nodes which directly depend on given node
+ *
+ * > result: list to write results to
+ * < node: the node to find the children/dependents of
+ */
+void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Get list of nodes which given node directly depends on
+ *
+ * > result: list to write results to
+ * < node: the node to find the dependencies of
+ */
+void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Topology Queries (Subgraph) -------------------- */
+// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
+// just spit out a copy of the subgraph which matches. This works well for the cases
+// where these are used - mostly for efficient updating of subsets of the nodes.
+
+// XXX: allow supplying a filter predicate to provide further filtering/pruning?
+
+
+/* Get all descendants of a node
+ *
+ * That is, get the subgraph / subset of nodes which are dependent
+ * on the results of the given node.
+ */
+Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
+
+
+/* Get all ancestors of a node
+ *
+ * That is, get the subgraph / subset of nodes which the given node
+ * is dependent on in order to be evaluated.
+ */
+Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
+
+/* ************************************************ */
+/* Higher-Level Queries */
+
+/* Get ID-blocks which would be affected if specified ID is modified
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+
+/* Get ID-blocks which are needed to update/evaluate specified ID
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+/* ************************************************ */
+
+/* Check if given ID type was tagged for update. */
+bool DEG_id_type_tagged(struct Main *bmain, short idtype);
+
+/* Get additional evaluation flags for the given ID. */
+short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_QUERY_H__ */
diff --git a/source/blender/depsgraph/SConscript b/source/blender/depsgraph/SConscript
new file mode 100644
index 00000000000..dd0552e19a2
--- /dev/null
+++ b/source/blender/depsgraph/SConscript
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# ***** 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) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Nathan Letwory, Joshua Leung.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import('env')
+
+sources = env.Glob('intern/*.cc') + env.Glob('util/*.cc')
+
+incs = [
+ '.',
+ './intern',
+ './util',
+ '#/intern/atomic',
+ '#/intern/guardedalloc',
+ '../bmesh',
+ '../blenlib',
+ '../blenkernel',
+ '../makesdna',
+ '../makesrna',
+ '../modifiers',
+ '../windowmanager',
+ ]
+
+defs = []
+
+if env['WITH_BF_BOOST']:
+ incs.append(env['BF_BOOST_INC'])
+ defs.append('HAVE_BOOST_FUNCTION_BINDINGS')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs.append(env['BF_PTHREADS_INC'])
+
+
+if env['WITH_UNORDERED_MAP_SUPPORT']:
+ if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
+ if env['UNORDERED_MAP_NAMESPACE'] == 'std':
+ defs.append('DEG_STD_UNORDERED_MAP')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_TR1_UNORDERED_MAP')
+else:
+ print("-- Replacing unordered_map/set with map/set (warning: slower!)")
+ defs.append('DEG_NO_UNORDERED_MAP')
+
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
+env.BlenderLib(libname='bf_depsgraph', sources=sources,
+ includes=incs, defines=defs,
+ libtype=['core', 'player'], priority=[200, 40])
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
new file mode 100644
index 00000000000..e9b2a06cf7b
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+
+extern "C" {
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_sequence_types.h"
+
+#include "RNA_access.h"
+}
+
+#include "DEG_depsgraph.h"
+#include "depsgraph.h" /* own include */
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsnode_component.h"
+#include "depsgraph_intern.h"
+
+static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
+static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
+
+Depsgraph::Depsgraph()
+ : root_node(NULL),
+ need_update(false),
+ layers((1 << 20) - 1)
+{
+ BLI_spin_init(&lock);
+}
+
+Depsgraph::~Depsgraph()
+{
+ /* Free root node - it won't have been freed yet... */
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ if (this->root_node != NULL) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ }
+ BLI_spin_end(&lock);
+}
+
+/* Query Conditions from RNA ----------------------- */
+
+static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id)
+{
+ if (!ptr->type)
+ return false;
+
+ if (!prop) {
+ if (RNA_struct_is_ID(ptr->type)) {
+ *id = (ID *)ptr->data;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id,
+ eDepsNode_Type *type,
+ string *subdata)
+{
+ if (!ptr->type)
+ return false;
+
+ /* Set default values for returns. */
+ *id = (ID *)ptr->id.data; /* For obvious reasons... */
+ *subdata = ""; /* Default to no subdata (e.g. bone) name
+ * lookup in most cases. */
+
+ /* Handling of commonly known scenarios... */
+ if (ptr->type == &RNA_PoseBone) {
+ bPoseChannel *pchan = (bPoseChannel *)ptr->data;
+
+ /* Bone - generally, we just want the bone component... */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Bone) {
+ Bone *bone = (Bone *)ptr->data;
+
+ /* 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;
+ *subdata = bone->name;
+ //*id = ...
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+ Object *ob = (Object *)ptr->id.data;
+ bConstraint *con = (bConstraint *)ptr->data;
+
+ /* object or bone? */
+ 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;
+ return true;
+ }
+ else if (ob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ /* bone transforms */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+ return true;
+ }
+ }
+ }
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+ //ModifierData *md = (ModifierData *)ptr->data;
+
+ /* Modifier */
+ /* NOTE: subdata is not the same as "operation name",
+ * so although we have unique ops for modifiers,
+ * we can't lump them together
+ */
+ *type = DEPSNODE_TYPE_BONE;
+ //*subdata = md->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Object) {
+ //Object *ob = (Object *)ptr->data;
+
+ /* Transforms props? */
+ if (prop) {
+ const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
+
+ if (strstr(prop_identifier, "location") ||
+ strstr(prop_identifier, "rotation") ||
+ strstr(prop_identifier, "scale"))
+ {
+ *type = DEPSNODE_TYPE_TRANSFORM;
+ 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;
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ Sequence *seq = (Sequence *)ptr->data;
+ /* Sequencer strip */
+ *type = DEPSNODE_TYPE_SEQUENCER;
+ *subdata = seq->name; // xxx?
+ return true;
+ }
+
+ if (prop) {
+ /* All unknown data effectively falls under "parameter evaluation" */
+ *type = DEPSNODE_TYPE_PARAMETERS;
+ return true;
+ }
+
+ return false;
+}
+
+/* Convenience wrapper to find node given just pointer + property. */
+DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
+ const PropertyRNA *prop) const
+{
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+
+ /* Get querying conditions. */
+ if (pointer_to_id_node_criteria(ptr, prop, &id)) {
+ return find_id_node(id);
+ }
+ else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node)
+ return id_node->find_component(type, name);
+ }
+
+ return NULL;
+}
+
+/* Node Management ---------------------------- */
+
+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)
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ SubgraphDepsNode *subgraph_node =
+ (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
+
+ /* Add to subnodes list. */
+ this->subgraphs.insert(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
+ }
+
+ return subgraph_node;
+}
+
+void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
+{
+ subgraphs.erase(subgraph_node);
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+}
+
+void Depsgraph::clear_subgraph_nodes()
+{
+ for (Subgraphs::iterator it = subgraphs.begin();
+ it != subgraphs.end();
+ ++it)
+ {
+ SubgraphDepsNode *subgraph_node = *it;
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+ }
+ subgraphs.clear();
+}
+
+IDDepsNode *Depsgraph::find_id_node(const ID *id) const
+{
+ IDNodeMap::const_iterator it = this->id_hash.find(id);
+ return it != this->id_hash.end() ? it->second : NULL;
+}
+
+IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (!id_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ id_node = (IDDepsNode *)factory->create_node(id, "", name);
+ id->flag |= LIB_DOIT;
+ /* register */
+ this->id_hash[id] = id_node;
+ }
+ return id_node;
+}
+
+void Depsgraph::remove_id_node(const ID *id)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node) {
+ /* unregister */
+ this->id_hash.erase(id);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+}
+
+void Depsgraph::clear_id_nodes()
+{
+ for (IDNodeMap::const_iterator it = id_hash.begin();
+ it != id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+ id_hash.clear();
+}
+
+/* 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);
+ return rel;
+}
+
+/* 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);
+ return rel;
+}
+
+/* ************************ */
+/* Relationships Management */
+
+DepsRelation::DepsRelation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+ : from(from),
+ to(to),
+ name(description),
+ type(type),
+ flag(0)
+{
+#ifndef NDEBUG
+/*
+ for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
+ it != from->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ if (rel->from == from &&
+ rel->to == to &&
+ rel->type == type &&
+ rel->name == description)
+ {
+ BLI_assert(!"Duplicated relation, should not happen!");
+ }
+ }
+*/
+#endif
+
+ /* Hook it up to the nodes which use it. */
+ from->outlinks.insert(this);
+ to->inlinks.insert(this);
+}
+
+DepsRelation::~DepsRelation()
+{
+ /* Sanity check. */
+ BLI_assert(this->from && this->to);
+ /* Remove it from the nodes that use it. */
+ this->from->outlinks.erase(this);
+ this->to->inlinks.erase(this);
+}
+
+/* Low level tagging -------------------------------------- */
+
+/* Tag a specific node as needing updates. */
+void Depsgraph::add_entry_tag(OperationDepsNode *node)
+{
+ /* Sanity check. */
+ if (!node)
+ return;
+
+ /* Add to graph-level set of directly modified nodes to start searching from.
+ * NOTE: this is necessary since we have several thousand nodes to play with...
+ */
+ this->entry_tags.insert(node);
+}
+
+void Depsgraph::clear_all_nodes()
+{
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ id_hash.clear();
+ if (this->root_node) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ root_node = NULL;
+ }
+}
+
+/* **************** */
+/* Public Graph API */
+
+/* Initialize a new Depsgraph */
+Depsgraph *DEG_graph_new()
+{
+ return OBJECT_GUARDED_NEW(Depsgraph);
+}
+
+/* Free graph's contents and graph itself */
+void DEG_graph_free(Depsgraph *graph)
+{
+ OBJECT_GUARDED_DELETE(graph, Depsgraph);
+}
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ deg_editor_update_id_cb = id_func;
+ deg_editor_update_scene_cb = scene_func;
+}
+
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
new file mode 100644
index 00000000000..9533fbd10d5
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -0,0 +1,224 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph.h
+ * \ingroup depsgraph
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_H__
+#define __DEPSGRAPH_H__
+
+#include "BLI_threads.h" /* for SpinLock */
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct PointerRNA;
+struct PropertyRNA;
+
+struct DepsNode;
+struct RootDepsNode;
+struct TimeSourceDepsNode;
+struct IDDepsNode;
+struct SubgraphDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+/* *************************** */
+/* Relationships Between Nodes */
+
+/* Settings/Tags on Relationship */
+typedef enum eDepsRelation_Flag {
+ /* "touched" tag is used when filtering, to know which to collect */
+ DEPSREL_FLAG_TEMP_TAG = (1 << 0),
+
+ /* "cyclic" link - when detecting cycles, this relationship was the one
+ * which triggers a cyclic relationship to exist in the graph
+ */
+ DEPSREL_FLAG_CYCLIC = (1 << 1),
+} eDepsRelation_Flag;
+
+/* B depends on A (A -> B) */
+struct DepsRelation {
+ /* the nodes in the relationship (since this is shared between the nodes) */
+ DepsNode *from; /* A */
+ DepsNode *to; /* B */
+
+ /* 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();
+};
+
+/* ********* */
+/* Depsgraph */
+
+/* Dependency Graph object */
+struct Depsgraph {
+ typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
+ typedef unordered_set<SubgraphDepsNode *> Subgraphs;
+ typedef unordered_set<OperationDepsNode *> EntryTags;
+ typedef vector<OperationDepsNode *> OperationNodes;
+
+ Depsgraph();
+ ~Depsgraph();
+
+ /**
+ * Find node which matches the specified description.
+ *
+ * \param id: ID block that is associated with this
+ * \param subdata: identifier used for sub-ID data (e.g. bone)
+ * \param type: type of node we're dealing with
+ * \param name: custom identifier assigned to node
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph.
+ */
+ DepsNode *find_node(const ID *id,
+ eDepsNode_Type type,
+ const string &subdata,
+ const string &name);
+
+ /**
+ * Convenience wrapper to find node given just pointer + property.
+ *
+ * \param ptr: pointer to the data that node will represent
+ * \param prop: optional property affected - providing this effectively results in inner nodes being returned
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph
+ */
+ 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();
+
+ IDDepsNode *find_id_node(const ID *id) const;
+ IDDepsNode *add_id_node(ID *id, const string &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. */
+ void add_entry_tag(OperationDepsNode *node);
+
+ /* Clear storage used by all nodes. */
+ void clear_all_nodes();
+
+ /* Core Graph Functionality ........... */
+
+ /* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
+ * (for quick lookups). */
+ IDNodeMap id_hash;
+
+ /* "root" node - the one where all evaluation enters from. */
+ RootDepsNode *root_node;
+
+ /* Subgraphs referenced in tree. */
+ Subgraphs subgraphs;
+
+ /* Indicates whether relations needs to be updated. */
+ bool need_update;
+
+ /* Quick-Access Temp Data ............. */
+
+ /* Nodes which have been tagged as "directly modified". */
+ EntryTags entry_tags;
+
+ /* Convenience Data ................... */
+
+ /* XXX: should be collected after building (if actually needed?) */
+ /* All operation nodes, sorted in order of single-thread traversal order. */
+ OperationNodes operations;
+
+ /* Spin lock for threading-critical operations.
+ * Mainly used by graph evaluation.
+ */
+ SpinLock lock;
+
+ /* Layers Visibility .................. */
+
+ /* Visible layers bitfield, used for skipping invisible objects updates. */
+ int layers;
+
+ // XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
+};
+
+/**
+ * Helper macros for iterating over set of relationship links
+ * incident on each node.
+ *
+ * \note it is safe to perform removal operations here...
+ *
+ * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
+ * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
+ * currently accessing comes up
+ */
+#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
+ { \
+ OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
+ while (__rel_iter != relations_set_.end()) { \
+ DepsRelation *relation_ = *__rel_iter; \
+ ++__rel_iter; \
+
+ /* ... code for iterator body can be written here ... */
+
+#define DEPSNODE_RELATIONS_ITER_END \
+ } \
+ } ((void)0)
+
+#endif /* __DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
new file mode 100644
index 00000000000..7a2ee2c416a
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -0,0 +1,370 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph.
+ */
+
+#include <stack>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsgraph_debug.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph_util_transitive.h"
+
+/* ****************** */
+/* External Build API */
+
+static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+{
+ switch (component) {
+ case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+{
+ switch (component) {
+ case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_scene_component_type(component);
+ ComponentKey comp_key(&scene->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type, bone_name);
+
+ // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
+{
+ if (graph == NULL) {
+ BLI_assert(!"Graph should always be valid");
+ return;
+ }
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ BLI_assert(!"ID should always be valid");
+ return;
+ }
+ id_node->eval_flags |= flag;
+}
+
+/* ********************** */
+/* Utilities for Builders */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ sprintf(index_buf, "[%d]", fcu->array_index);
+
+ return string(fcu->rna_path) + index_buf;
+}
+
+static void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode *> stack;
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->done = 0;
+ node->num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ }
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->id->flag |= LIB_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ if (node->done == 0 && node->outlinks.size() != 0) {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(to->num_links_pending > 0);
+ --to->num_links_pending;
+ }
+ if (to->num_links_pending == 0) {
+ stack.push(to);
+ }
+ }
+ }
+ node->done = 1;
+ }
+ else {
+ stack.pop();
+ IDDepsNode *id_node = node->owner->owner;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ IDDepsNode *id_to = to->owner->owner;
+ id_node->layers |= id_to->layers;
+ }
+ }
+
+ /* Re-tag ID for update if it was tagged before the relations
+ * update tag.
+ */
+ ID *id = id_node->id;
+ if (id->flag & LIB_ID_RECALC_ALL &&
+ id->flag & LIB_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+}
+
+/* ******************** */
+/* Graph Building API's */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+// XXX: assume that this is called from outside, given the current scene as the "main" scene
+void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
+{
+ /* 1) Generate all the nodes in the graph first */
+ DepsgraphNodeBuilder node_builder(bmain, 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.build_scene(bmain, scene);
+
+ /* 2) Hook up relationships between operations - to determine evaluation order */
+ DepsgraphRelationBuilder relation_builder(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.
+ */
+ //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+ relation_builder.build_scene(bmain, scene);
+
+ /* Detect and solve cycles. */
+ deg_graph_detect_cycles(graph);
+
+ /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
+ // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ if (G.debug_value == 799) {
+ deg_graph_transitive_reduction(graph);
+ }
+
+ /* 4) Flush visibility layer and re-schedule nodes for update. */
+ deg_graph_build_finalize(graph);
+
+#if 0
+ if (!DEG_debug_consistency_check(graph)) {
+ printf("Consistency validation failed, ABORTING!\n");
+ abort();
+ }
+#endif
+}
+
+/* Tag graph relations for update. */
+void DEG_graph_tag_relations_update(Depsgraph *graph)
+{
+ graph->need_update = true;
+}
+
+/* Tag all relations for update. */
+void DEG_relations_tag_update(Main *bmain)
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ }
+}
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph == NULL) {
+ /* Rebuild graph from scratch and exit. */
+ scene->depsgraph = DEG_graph_new();
+ DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
+ return;
+ }
+
+ Depsgraph *graph = scene->depsgraph;
+ if (!graph->need_update) {
+ /* Graph is up to date, nothing to do. */
+ return;
+ }
+
+ /* Clear all previous nodes and operations. */
+ graph->clear_all_nodes();
+ graph->operations.clear();
+ graph->entry_tags.clear();
+
+ /* Build new nodes and relations. */
+ DEG_graph_build_from_scene(graph, bmain, scene);
+
+ graph->need_update = false;
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DEG_scene_graph_free(Scene *scene)
+{
+ if (scene->depsgraph) {
+ DEG_graph_free(scene->depsgraph);
+ scene->depsgraph = NULL;
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/depsgraph_build.h
new file mode 100644
index 00000000000..4088a3289ef
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.h
@@ -0,0 +1,408 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_BUILD_H__
+#define __DEPSGRAPH_BUILD_H__
+
+struct Base;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsNodeHandle;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+struct RootPChanMap;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
+ {
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+ }
+
+ bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
+ eDepsOperation_Code opcode, const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "")
+ {
+ return find_operation_node(id, comp_type, "", opcode, description);
+ }
+
+ 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_rigidbody(Scene *scene);
+ void build_particles(Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ 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_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+
+private:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+struct RootKey
+{
+ RootKey() {}
+};
+
+struct TimeSourceKey
+{
+ TimeSourceKey() : id(NULL) {}
+ TimeSourceKey(ID *id) : id(id) {}
+
+ string identifier() const
+ {
+ return string("TimeSourceKey");
+ }
+
+ ID *id;
+};
+
+struct ComponentKey
+{
+ ComponentKey() :
+ id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
+ {}
+ ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
+ id(id), type(type), name(name)
+ {}
+
+ string identifier() const
+ {
+ const char *idname = (id) ? id->name : "<None>";
+
+ char typebuf[5];
+ sprintf(typebuf, "%d", type);
+
+ return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
+ }
+
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+};
+
+struct OperationKey
+{
+ OperationKey() :
+ id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char typebuf[5];
+ sprintf(typebuf, "%d", component_type);
+
+ return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
+ }
+
+
+ ID *id;
+ eDepsNode_Type component_type;
+ string component_name;
+ eDepsOperation_Code opcode;
+ string name;
+};
+
+struct RNAPathKey
+{
+ // Note: see depsgraph_build.cpp for implementation
+ RNAPathKey(ID *id, const char *path);
+
+ RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
+ id(id), ptr(ptr), prop(prop)
+ {}
+
+ string identifier() const
+ {
+ const char *id_name = (id) ? id->name : "<No ID>";
+ const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
+
+ return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')";
+ }
+
+
+ ID *id;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+};
+
+struct DepsgraphRelationBuilder
+{
+ DepsgraphRelationBuilder(Depsgraph *graph);
+
+ 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);
+ void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
+ void build_object(Main *bmain, Scene *scene, Object *ob);
+ void build_object_parent(Object *ob);
+ void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
+ ListBase *constraints, RootPChanMap *root_map);
+ void build_animdata(ID *id);
+ void build_driver(ID *id, FCurve *fcurve);
+ void build_world(World *world);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(ID *obdata, Key *key);
+ 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_compositor(Scene *scene);
+ void build_gpencil(ID *owner, bGPdata *gpd);
+
+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;
+ DepsNode *find_node(const RNAPathKey &key) const;
+ OperationDepsNode *has_node(const OperationKey &key) const;
+
+ void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
+ void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyType>
+ DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+
+ bool needs_animdata_node(ID *id);
+
+private:
+ Depsgraph *m_graph;
+};
+
+struct DepsNodeHandle
+{
+ DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
+ builder(builder),
+ node(node),
+ default_name(default_name)
+ {
+ BLI_assert(node != NULL);
+ }
+
+ DepsgraphRelationBuilder *builder;
+ OperationDepsNode *node;
+ const string &default_name;
+};
+
+/* Utilities for Builders ----------------------------------------------------- */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+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);
+ DepsNode *node_to = find_node(key_to);
+ 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);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
+ type, 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());
+ }
+ 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());
+ }
+ else {
+ fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
+ type, description, key_to.identifier().c_str());
+ }
+ }
+}
+
+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;
+ if (time_from && op_to) {
+ add_time_relation(time_from, op_to, description);
+ }
+ else {
+ }
+}
+
+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);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ }
+}
+
+template <typename KeyType>
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
+ const string &default_name)
+{
+ return DepsNodeHandle(this, find_node(key), default_name);
+}
+
+#endif /* __DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
new file mode 100644
index 00000000000..31e32ac3e75
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -0,0 +1,1204 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_idcode.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#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 "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+/* ************ */
+/* Node Builder */
+
+/* **** General purpose functions **** */
+
+DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) :
+ m_bmain(bmain),
+ m_graph(graph)
+{
+}
+
+DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
+{
+}
+
+RootDepsNode *DepsgraphNodeBuilder::add_root_node()
+{
+ return m_graph->add_root_node();
+}
+
+IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
+{
+ const char *idtype_name = BKE_idcode_to_name(GS(id->name));
+ return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]");
+}
+
+TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
+{
+ /* 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;
+}
+
+ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name)
+{
+ IDDepsNode *id_node = add_id_node(id);
+ ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name);
+ comp_node->owner = id_node;
+ return comp_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ OperationDepsNode *op_node = comp_node->has_operation(opcode, description);
+ if (op_node == NULL) {
+ op_node = comp_node->add_operation(optype, op, opcode, description);
+ m_graph->operations.push_back(op_node);
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ comp_node->identifier().c_str(),
+ op_node->identifier().c_str(),
+ op_node);
+ BLI_assert(!"Should not happen!");
+ }
+ return op_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return add_operation_node(comp_node, optype, op, opcode, description);
+}
+
+bool DepsgraphNodeBuilder::has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return comp_node->has_operation(opcode, description);
+}
+
+
+/* **** Build functions for entity nodes **** */
+
+void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_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, false);
+
+ /* scene ID block */
+ add_id_node(&scene->id);
+
+ /* timesource */
+ add_time_source(NULL);
+
+ /* build subgraph for set, and link this in... */
+ // XXX: depending on how this goes, that scene itself could probably store its
+ // own little partial depsgraph?
+ if (scene->set) {
+ build_scene(bmain, scene->set);
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(scene, base, ob);
+
+ /* object that this is a proxy for */
+ // XXX: the way that proxies work needs to be completely reviewed!
+ if (ob->proxy) {
+ build_object(scene, base, ob->proxy);
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group) {
+ build_group(scene, base, ob->dup_group);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* sequencer */
+ // XXX...
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(scene->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_group(Scene *scene,
+ Base *base,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ if (group_id->flag & LIB_DOIT) {
+ return;
+ }
+ group_id->flag |= LIB_DOIT;
+
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ build_object(scene, base, go->ob);
+ }
+}
+
+SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
+{
+ /* sanity checks */
+ if (!group)
+ return NULL;
+
+ /* create new subgraph's data */
+ Depsgraph *subgraph = DEG_graph_new();
+
+ DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
+
+ /* add group objects */
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ /*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)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
+ id_node->layers = base->lay;
+ return;
+ }
+
+ IDDepsNode *id_node = add_id_node(&ob->id);
+ id_node->layers = base->lay;
+
+ /* standard components */
+ build_object_transform(scene, ob);
+
+
+ /* object data */
+ if (ob->data) {
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ /* 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");
+
+ build_obdata_geom(scene, ob);
+ /* TODO(sergey): Only for until we support granular
+ * update of curves.
+ */
+ if (ob->type == OB_FONT) {
+ Curve *curve = (Curve *)ob->data;
+ if (curve->textoncurve) {
+ id_node->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
+ }
+ }
+ break;
+ }
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+
+ default:
+ {
+ ID *obdata = (ID *)ob->data;
+ if ((obdata->flag & LIB_DOIT) == 0) {
+ build_animdata(obdata);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Build animation data,
+ *
+ * Do it now because it's possible object data will affect
+ * on object's level animation, for example in case of rebuilding
+ * pose for proxy.
+ */
+ build_animdata(&ob->id);
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(ob->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
+{
+ /* 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);
+
+ /* 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),
+ DEG_OPCODE_TRANSFORM_PARENT);
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ build_object_constraints(scene, ob);
+ }
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * 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),
+ 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);
+}
+
+/**
+ * Constraints Graph Notes
+ *
+ * For constraints, we currently only add a operation node to the Transform
+ * or Bone components (depending on whichever type of owner we have).
+ * This represents the entire constraints stack, which is for now just
+ * executed as a single monolithic block. At least initially, this should
+ * be sufficient for ensuring that the porting/refactoring process remains
+ * manageable.
+ *
+ * However, when the time comes for developing "node-based" constraints,
+ * we'll need to split this up into pre/post nodes for "constraint stack
+ * evaluation" + operation nodes for each constraint (i.e. the contents
+ * of the loop body used in the current "solve_constraints()" operation).
+ *
+ * -- Aligorith, August 2013
+ */
+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),
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+}
+
+void DepsgraphNodeBuilder::build_pose_constraints(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),
+ DEG_OPCODE_BONE_CONSTRAINTS);
+}
+
+/**
+ * Build graph nodes for AnimData block
+ * \param id: ID-Block which hosts the AnimData
+ */
+void DepsgraphNodeBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ /* animation */
+ if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ /* 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),
+ 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
+ // (which will be needed for proper handling of drivers later)
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ /* create driver */
+ build_driver(id, fcu);
+ }
+ }
+}
+
+/**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcu: Driver-FCurve
+ */
+OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+
+ /* Create data node for this driver */
+ /* TODO(sergey): Avoid creating same operation multiple times,
+ * in the future we need to avoid lookup of the operation as well
+ * and use some tagging magic instead.
+ */
+ OperationDepsNode *driver_op = find_operation_node(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ deg_fcurve_id_name(fcu));
+
+ if (driver_op == NULL) {
+ driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu),
+ DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ }
+
+ /* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ driver_op->flag |= DEPSOP_FLAG_USES_PYTHON;
+ }
+
+ /* return driver node created */
+ return driver_op;
+}
+
+/* Recursively build graph for world */
+void DepsgraphNodeBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* world itself */
+ IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_node, world->mtex);
+
+ /* world's nodetree */
+ if (world->nodetree) {
+ build_nodetree(world_node, world->nodetree);
+ }
+}
+
+/* Rigidbody Simulation - Scene Level */
+void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ /**
+ * Rigidbody Simulation Nodes
+ * ==========================
+ *
+ * There are 3 nodes related to Rigidbody Simulation:
+ * 1) "Initialize/Rebuild World" - this is called sparingly, only when the simulation
+ * needs to be rebuilt (mainly after file reload, or moving back to start frame)
+ * 2) "Do Simulation" - perform a simulation step - interleaved between the evaluation
+ * steps for clusters of objects (i.e. between those affected and/or not affected by
+ * the sim for instance)
+ *
+ * 3) "Pull Results" - grab the specific transforms applied for a specific object -
+ * performed as part of object's transform-stack building
+ */
+
+ /* create nodes ------------------------------------------------------------------------ */
+ /* 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),
+ 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),
+ DEG_OPCODE_RIGIDBODY_SIM);
+
+ /* XXX: For now, the sim node is the only one that really matters here. If any other
+ * sims get added later, we may have to remove these hacks...
+ */
+ sim_node->owner->entry_operation = sim_node;
+ sim_node->owner->exit_operation = sim_node;
+
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+
+ if (!ob || (ob->type != OB_MESH))
+ continue;
+
+ /* 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),
+ DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_particles(Object *ob)
+{
+ /**
+ * Particle Systems Nodes
+ * ======================
+ *
+ * There are two types of nodes associated with representing
+ * particle systems:
+ * 1) Component (EVAL_PARTICLES) - This is the particle-system
+ * evaluation context for an object. It acts as the container
+ * for all the nodes associated with a particular set of particle
+ * systems.
+ * 2) Particle System Eval Operation - This operation node acts as a
+ * blackbox evaluation step for one particle system referenced by
+ * the particle systems stack. All dependencies link to this operation.
+ */
+
+ /* component for all particle systems */
+ ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ // XXX: what if this is used more than once!
+ build_animdata(&part->id);
+
+ /* 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, ob, psys),
+ DEG_OPCODE_PSYS_EVAL,
+ psys->name);
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* 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,
+ 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),
+ DEG_OPCODE_POSE_IK_SOLVER);
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+
+ /* 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),
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
+{
+ bArmature *arm = (bArmature *)ob->data;
+
+ /* animation and/or drivers linking posebones to base-armature used to define them
+ * NOTE: AnimData here is really used to control animated deform properties,
+ * which ideally should be able to be unique across different instances.
+ * 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);
+
+ /* Rebuild pose if not up to date. */
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ BKE_pose_rebuild(ob, arm);
+ /* XXX: Without this animation gets lost in certain circumstances
+ * after loading file. Need to investigate further since it does
+ * not happen with simple scenes..
+ */
+ if (ob->adt) {
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+ }
+
+ /**
+ * Pose Rig Graph
+ * ==============
+ *
+ * Pose Component:
+ * - Mainly used for referencing Bone components.
+ * - This is where the evaluation operations for init/exec/cleanup
+ * (ik) solvers live, and are later hooked up (so that they can be
+ * interleaved during runtime) with bone-operations they depend on/affect.
+ * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
+ * steps of pose eval process. ALL bone operations must be performed
+ * between these two...
+ *
+ * Bone Component:
+ * - Used for representing each bone within the rig
+ * - Acts to encapsulate the evaluation operations (base matrix + parenting,
+ * and constraint stack) so that they can be easily found.
+ * - Everything else which depends on bone-results hook up to the component only
+ * so that we can redirect those to point at either the the post-IK/
+ * post-constraint/post-matrix steps, as needed.
+ */
+
+ /* 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);
+
+ /* bones */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* 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);
+
+ 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
+ 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 */
+ 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);
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ build_pose_constraints(ob, pchan);
+ }
+
+ /**
+ * IK Solvers...
+ *
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(scene, ob, pchan, con);
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(scene, ob, pchan, con);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+ build_animdata(obdata);
+
+ 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);
+
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_INIT, NULL,
+ DEG_OPCODE_BONE_LOCAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_BONE_READY);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_BONE_DONE);
+ }
+
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_POST,
+ NULL,
+ DEG_OPCODE_POSE_DONE);
+}
+
+/* Shapekeys */
+void DepsgraphNodeBuilder::build_shapekeys(Key *key)
+{
+ build_animdata(&key->id);
+
+ add_operation_node(&key->id, DEPSNODE_TYPE_GEOMETRY, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Shapekey Eval");
+}
+
+/* ObData Geometry Evaluation */
+// XXX: what happens if the datablock is shared!
+void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * 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");
+
+ // TODO: "Done" operation
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key)
+ build_shapekeys(key);
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ 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);
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma) {
+ // XXX?!
+ ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+ build_material(geom_node, ma);
+ }
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(obdata);
+
+ /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ //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");
+ break;
+ }
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ 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");
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ /* curve 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. */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
+ DEG_OPCODE_GEOMETRY_PATH, "Path");
+ break;
+ }
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ /* nurbs evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ break;
+ }
+
+ case OB_LATTICE: /* 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");
+ break;
+ }
+ }
+
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Done");
+
+ /* Parameters for driver sources. */
+ add_operation_node(obdata, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+}
+
+/* Cameras */
+void DepsgraphNodeBuilder::build_camera(Object *ob)
+{
+ /* TODO: Link scene-camera links in somehow... */
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&cam->id);
+
+ add_operation_node(camera_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, 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");
+ }
+}
+
+/* Lamps */
+void DepsgraphNodeBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&la->id);
+
+ /* node for obdata */
+ ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_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,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* lamp's nodetree */
+ if (la->nodetree) {
+ build_nodetree(param_node, la->nodetree);
+ }
+
+ /* textures */
+ build_texture_stack(param_node, la->mtex);
+}
+
+void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ /* nodetree itself */
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* Parameters for drivers. */
+ add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner_node, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner_node, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner_node, ntree);
+ }
+ }
+ }
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* material itself */
+ add_id_node(ma_id);
+
+ add_operation_node(ma_id, DEPSNODE_TYPE_SHADING,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Material Update");
+
+ /* material animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner_node, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner_node, ma->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner_node, mtex->tex);
+ }
+}
+
+/* Recursively build graph for texture */
+void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+ /* texture itself */
+ build_animdata(tex_id);
+ /* texture's nodetree */
+ build_nodetree(owner_node, tex->nodetree);
+}
+
+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);
+
+ /* 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);
+}
+
+void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
+{
+ ID *gpd_id = &gpd->id;
+
+ /* gpencil itself */
+ // XXX: what about multiple users of same datablock? This should only get added once
+ add_id_node(gpd_id);
+
+ /* The main reason Grease Pencil is included here is because the animation (and drivers)
+ * need to be hosted somewhere...
+ */
+ build_animdata(gpd_id);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
new file mode 100644
index 00000000000..41c8054c53a
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -0,0 +1,1852 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build_relations.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#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 "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_build.h"
+#include "depsgraph_debug.h"
+#include "depsgraph_intern.h"
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_pchanmap.h"
+
+/* ***************** */
+/* Relations Builder */
+
+/* **** General purpose functions **** */
+
+RNAPathKey::RNAPathKey(ID *id, const char *path) :
+ id(id)
+{
+ /* create ID pointer for root of path lookup */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ /* try to resolve path... */
+ int index;
+ if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) {
+ this->ptr = PointerRNA_NULL;
+ this->prop = NULL;
+ }
+}
+
+DepsgraphRelationBuilder::DepsgraphRelationBuilder(Depsgraph *graph) :
+ m_graph(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
+{
+ if (key.id) {
+ /* XXX TODO */
+ return NULL;
+ }
+ else {
+ return m_graph->root_node->time_source;
+ }
+}
+
+ComponentDepsNode *DepsgraphRelationBuilder::find_node(
+ const ComponentKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node component: Could not find ID %s\n",
+ (key.id != NULL) ? key.id->name : "<null>");
+ return NULL;
+ }
+
+ ComponentDepsNode *node = id_node->find_component(key.type, key.name);
+ return node;
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::find_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node operation: Could not find ID\n");
+ return NULL;
+ }
+
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ fprintf(stderr, "find_node operation: Could not find component\n");
+ return NULL;
+ }
+
+ OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name);
+ if (!op_node) {
+ fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
+ DEG_OPNAMES[key.opcode], key.name.c_str());
+ }
+ return op_node;
+}
+
+DepsNode *DepsgraphRelationBuilder::find_node(const RNAPathKey &key) const
+{
+ return m_graph->find_node_from_pointer(&key.ptr, key.prop);
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::has_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ return NULL;
+ }
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ return NULL;
+ }
+ return comp_node->has_operation(key.opcode, key.name);
+}
+
+void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description)
+{
+ if (timesrc && node_to) {
+ m_graph->add_new_relation(timesrc, node_to, DEPSREL_TYPE_TIME, description);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
+ timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>",
+ node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
+ description);
+ }
+}
+
+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);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %d, %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);
+ }
+}
+
+/* **** Functions to build relations between entities **** */
+
+void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, false);
+
+ if (scene->set) {
+ // TODO: link set to scene, especially our timesource...
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(bmain, scene, ob);
+
+ /* object that this is a proxy for */
+ if (ob->proxy) {
+ 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 */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(&scene->id, scene->gpd);
+ }
+}
+
+void DepsgraphRelationBuilder::build_group(Main *bmain,
+ Scene *scene,
+ Object *object,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ bool group_done = (group_id->flag & LIB_DOIT) != 0;
+ OperationKey object_local_transform_key(&object->id,
+ DEPSNODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ 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");
+ }
+ group_id->flag |= LIB_DOIT;
+}
+
+void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *ob)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ return;
+ }
+
+ /* 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 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 ob_ubereval_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+
+ /* parenting */
+ if (ob->parent) {
+ /* parent relationship */
+ build_object_parent(ob);
+
+ /* local -> parent */
+ add_relation(local_transform_key, parent_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObLocal -> ObParent]");
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ OperationKey constraint_key(&ob->id, DEPSNODE_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);
+
+ /* 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]");
+
+ // 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");
+ }
+ 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");
+ }
+
+
+ /* AnimData */
+ build_animdata(&ob->id);
+
+ // XXX: This should be hooked up by the build_animdata code
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
+ }
+
+
+ /* object data */
+ if (ob->data) {
+ ID *obdata_id = (ID *)ob->data;
+
+ /* ob data animation */
+ build_animdata(obdata_id);
+
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ build_obdata_geom(bmain, scene, ob);
+ break;
+ }
+
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+ }
+
+ 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");
+ }
+ }
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(scene, ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(&ob->id, ob->gpd);
+ }
+}
+
+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);
+
+ /* 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");
+ 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");
+ /* XXX not sure what this is for or how you could be done properly - lukas */
+ //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");
+ 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");
+ break;
+ }
+
+ default:
+ {
+ 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);
+
+ 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");
+ }
+ 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 transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "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");
+ }
+ }
+ else {
+ /* Standard Parent */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Parent");
+ }
+ break;
+ }
+ }
+
+ /* exception case: parent is duplivert */
+ if ((ob->type == OB_MBALL) && (ob->parent->transflag & OB_DUPLIVERTS)) {
+ //dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
+ }
+}
+
+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 */
+ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ /* 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)) {
+ 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])
+ 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);
+ }
+ }
+ 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);
+ }
+
+ /* tracker <-> constraints */
+ // FIXME: actually motionclip dependency on results of motionclip block here...
+ //dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ }
+ else if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+ cti->get_constraint_targets(con, &targets);
+
+ for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ if (!ct->tar)
+ continue;
+
+ 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 ((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
+ */
+ 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);
+ }
+ 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);
+ }
+ }
+ 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);
+
+ if (ct->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ 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);
+ }
+ else {
+ /* 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)...
+ */
+ 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);
+ }
+ 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);
+ }
+ }
+ 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);
+ }
+ }
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_ROTLIKE,
+ CONSTRAINT_TYPE_SIZELIKE,
+ CONSTRAINT_TYPE_LOCLIKE,
+ 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);
+ }
+
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ ComponentKey adt_key(id, DEPSNODE_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]");
+
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+
+ /* create the driver's relations to targets */
+ build_driver(id, fcu);
+
+ /* 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]");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ bPoseChannel *pchan = NULL;
+
+ /* 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");
+
+ /* 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) {
+ /* interleaved drivers during bone eval */
+ // 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[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+
+ if (bone_name) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+
+ 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]");
+ }
+ else {
+ fprintf(stderr,
+ "Couldn't find bone name for driver path - '%s'\n",
+ fcu->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
+ */
+ IDDepsNode *arm_node = m_graph->find_id_node(id);
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ if (arm_node && bone_name) {
+ /* find objects which use this, and make their eval callbacks depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
+ {
+ IDDepsNode *to_node = (IDDepsNode *)rel->to;
+
+ /* 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]");
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ /* 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);
+ }
+ }
+ 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_KE && strstr(fcu->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]");
+ }
+ 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]");
+ }
+ 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]");
+ }
+ }
+
+ /* 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 */
+ for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == NULL)
+ continue;
+
+ /* 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);
+ if (target_pchan != NULL) {
+ /* 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)
+ * - Relations inside an IK chain (TODO?)
+ */
+ if (dtar->id == id &&
+ pchan != NULL &&
+ STREQ(pchan->name, target_pchan->name))
+ {
+ 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]");
+ }
+ }
+ 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]");
+ }
+ 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)
+ */
+ 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) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+ if (target_pchan) {
+ 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]");
+ }
+ }
+ else {
+ /* 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]");
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
+void DepsgraphRelationBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+ world_id->flag |= LIB_DOIT;
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_id, world->mtex);
+
+ /* world's nodetree */
+ build_nodetree(world_id, world->nodetree);
+}
+
+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);
+
+ /* rel between the two sim-nodes */
+ add_relation(init_key, sim_key, DEPSREL_TYPE_OPERATION, "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");
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || ob->type != OB_MESH)
+ continue;
+
+ /* hook up evaluation order...
+ * 1) flushing rigidbody results follows base transforms being applied
+ * 2) rigidbody flushing can only be performed after simulation has been run
+ *
+ * 3) simulation needs to know base transforms to figure out what to do
+ * 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);
+
+ eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
+ OperationKey trans_op(&ob->id, DEPSNODE_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");
+
+ /* 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)
+ * while still allowing the sim to depend on some changes to the objects.
+ * Also, since constraints are hooked up to the final nodes, this link
+ * means that we can also fit in there too...
+ * - Later, it might be good to include a constraint in the stack allowing us
+ * 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");
+ }
+ 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)");
+ }
+
+
+ /* needed to get correct base values */
+ add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval");
+ }
+ }
+
+ /* constraints */
+ if (rbw->constraints) {
+ for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || !ob->rigidbody_constraint)
+ continue;
+
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+
+ /* 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);
+
+ /* - 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");
+
+ /* - ensure that sim depends on this constraint's transform */
+ add_relation(trans_key, sim_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint Transform -> RB Simulation");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
+{
+ TimeSourceKey time_src_key;
+ OperationKey obdata_ubereval_key(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ build_animdata(&part->id);
+
+ /* this particle system */
+ OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
+
+ /* XXX: if particle system is later re-enabled, we must do full rebuild? */
+ if (!psys_check_enabled(ob, psys))
+ 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");
+
+ /* 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)) {
+ ParticleTarget *pt;
+
+ for (pt = psys->targets.first; pt; pt = pt->next) {
+ 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) {
+ for (go = part->dup_group->gobject.first; go; go = go->next) {
+ node2 = dag_get_node(dag, go->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
+ }
+ }
+#endif
+
+ /* effectors */
+ ListBase *effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (eff->psys) {
+ // XXX: DAG_RL_DATA_DATA | DAG_RL_OB_DATA
+ ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY); // xxx: particles instead?
+ add_relation(eff_key, psys_key, DEPSREL_TYPE_STANDARD, "Particle Field");
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+
+ /* boids */
+ if (part->boids) {
+ BoidRule *rule = NULL;
+ BoidState *state = NULL;
+
+ for (state = (BoidState *)part->boids->states.first; state; state = state->next) {
+ for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) {
+ Object *ruleob = NULL;
+ if (rule->type == eBoidRuleType_Avoid)
+ ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
+ else if (rule->type == eBoidRuleType_FollowLeader)
+ 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");
+ }
+ }
+ }
+ }
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* attach owner to IK Solver too
+ * - assume that owner is always part of chain
+ * - 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);
+
+ /* IK target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->tar != NULL) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ *
+ * This way we ensuring the whole subtree is updated from scratch without
+ * need of intermediate matricies. This is an overkill, but good enough for
+ * testing IK solver.
+ */
+ // FIXME: geometry targets...
+ ComponentKey pose_key(&ob->id, DEPSNODE_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);
+ }
+ 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);
+ }
+ }
+ 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);
+
+ if (data->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ /* Standard Object Target */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+
+ if ((data->tar == ob) && (data->subtarget[0])) {
+ /* Prevent target's constraints from linking to anything from same
+ * chain that it controls.
+ */
+ root_map->add_bone(data->subtarget, rootchan->name);
+ }
+ }
+
+ /* Pole Target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->poletar != NULL) {
+ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+ // XXX: same armature issues - ready vs done?
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ else if (ELEM(data->poletar->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->poletar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+ if (data->poletar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ }
+
+ DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
+ pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
+
+ bPoseChannel *parchan = pchan;
+ /* exclude tip from chain? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(solver_key, tip_transforms_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ parchan = pchan->parent;
+ }
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parchan_transforms_key, solver_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ while (parchan) {
+ /* Make IK-solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * 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 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");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
+ segcount++;
+ if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
+
+ 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");
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ 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);
+
+ /* 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");
+
+ /* attach path dependency to solver */
+ if (data->tar) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ * 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");
+ }
+
+ 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");
+
+ root_map->add_bone(pchan->name, rootchan->name);
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
+ /* Make Spline IK solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * 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 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");
+ }
+ 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");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ segcount++;
+ 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");
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
+{
+ /* Armature-Data */
+ // 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);
+
+ add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
+ }
+
+ /* IK Solvers...
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * - We build relations for these before the dependencies
+ * between ops in the same component as it is necessary
+ * to check whether such bones are in the same IK chain
+ * (or else we get weird issues with either in-chain
+ * references, or with bones being parented to IK'd bones)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ RootPChanMap root_map;
+ bool pose_depends_on_local_transform = false;
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_TRANSLIKE:
+ /* TODO(sergey): Add used space check. */
+ pose_depends_on_local_transform = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ //root_map.print_debug();
+
+ if (pose_depends_on_local_transform) {
+ /* 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");
+ }
+
+
+ /* links between operations for each bone */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ 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);
+
+ pchan->flag &= ~POSE_DONE;
+
+ /* pose init to bone local */
+ add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
+
+ /* local to pose parenting operation */
+ add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
+
+ /* parent relation */
+ if (pchan->parent != NULL) {
+ eDepsOperation_Code parent_key_opcode;
+
+ /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+ if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
+ parent_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ 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]");
+ }
+
+ /* 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);
+
+ /* 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");
+
+ /* 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");
+ }
+ else {
+ /* pose -> ready */
+ add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
+ }
+
+ /* bone ready -> done
+ * NOTE: For bones without IK, this is all that's needed.
+ * 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");
+
+ /* 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");
+ }
+}
+
+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);
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ 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");
+ }
+}
+
+/* Shapekeys */
+void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
+{
+ ComponentKey obdata_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+
+ /* attach animdata to geometry */
+ build_animdata(&key->id);
+
+ 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");
+ }
+
+ /* NOTE: individual shapekey drivers are handled above already */
+ }
+
+ /* 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");
+}
+
+/**
+ * ObData Geometry Evaluation
+ * ==========================
+ *
+ * The evaluation of geometry on objects is as follows:
+ * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.)
+ * occurs in the Geometry component of the object which references this. This includes
+ * modifiers, and the temporary "ubereval" for geometry.
+ * - Therefore, each user of a piece of shared geometry data ends up evaluating its own
+ * version of the stuff, complete with whatever modifiers it may use.
+ *
+ * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for
+ * 1) calculating the bounding boxes of the geometry data,
+ * 2) aggregating inward links from other objects (e.g. for text on curve, etc.)
+ * and also for the links coming from the shapekey datablocks
+ * - Animation/Drivers affecting the parameters of the geometry are made to trigger
+ * updates on the obdata geometry component, which then trigger downstream
+ * re-evaluation of the individual instances of this geometry.
+ */
+// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry?
+void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Object *ob)
+{
+ 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");
+
+ /* 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);
+
+ /* link components to each other */
+ add_relation(obdata_geom_key, geom_key, DEPSREL_TYPE_DATABLOCK, "Object Geometry Base Data");
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+ OperationKey prev_mod_key;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ 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);
+ mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ }
+
+ if (BKE_object_modifier_use_time(ob, md)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
+ }
+
+ prev_mod_key = mod_key;
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma)
+ build_material(&ob->id, ma);
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ /* Make sure uber update is the last in the dependencies.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ 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");
+ }
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+ obdata->flag |= LIB_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");
+
+ /* type-specific node/links */
+ switch (ob->type) {
+ case OB_MESH:
+ break;
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ if (mom != ob) {
+ /* non-motherball -> cannot be directly evaluated! */
+ ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ Curve *cu = (Curve *)obdata;
+
+ /* 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);
+ add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
+ }
+ if (cu->taperobj) {
+ ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
+ }
+ if (ob->type == OB_FONT) {
+ if (cu->textoncurve) {
+ ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
+ }
+ }
+ break;
+ }
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ break;
+ }
+
+ case OB_LATTICE: /* Lattice */
+ {
+ break;
+ }
+ }
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ build_shapekeys(obdata, key);
+ }
+
+ 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");
+ }
+}
+
+/* Cameras */
+// TODO: Link scene-camera links in somehow...
+void DepsgraphRelationBuilder::build_camera(Object *ob)
+{
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+ camera_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(camera_id, DEPSNODE_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");
+ }
+
+ /* 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");
+ }
+}
+
+/* Lamps */
+void DepsgraphRelationBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+ lamp_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(lamp_id, DEPSNODE_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");
+ }
+
+ /* 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");
+ }
+
+ /* textures */
+ build_texture_stack(lamp_id, la->mtex);
+}
+
+void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner, ntree);
+ ntree_id->flag |= LIB_DOIT;
+ }
+ }
+ }
+ }
+
+ if (needs_animdata_node(ntree_id)) {
+ ComponentKey parameters_key(ntree_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+ ma_id->flag |= LIB_DOIT;
+
+ /* animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner, ma->nodetree);
+}
+
+/* Recursively build graph for texture */
+void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+
+ /* texture itself */
+ build_animdata(tex_id);
+
+ /* texture's nodetree */
+ build_nodetree(owner, tex->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner, mtex->tex);
+ }
+}
+
+void DepsgraphRelationBuilder::build_compositor(Scene *scene)
+{
+ /* For now, just a plain wrapper? */
+ build_nodetree(&scene->id, scene->nodetree);
+}
+
+void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+{
+ /* animation */
+ build_animdata(&gpd->id);
+
+ // TODO: parent object (when that feature is implemented)
+}
+
+bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ return adt->action != NULL;
+ }
+ return false;
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
new file mode 100644
index 00000000000..59351495df0
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -0,0 +1,1193 @@
+/*
+ * ***** 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.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_debug.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+//#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+static SpinLock lock;
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#if 0
+static const char *deg_debug_colors_dark[] = {
+ "#6e8997", "#144f77", "#76945b",
+ "#216a1d", "#a76665", "#971112",
+ "#a87f49", "#0a9540", "#86768e",
+ "#462866", "#a9a965", "#753b1a",
+};
+#endif
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#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},
+
+ /* 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},
+ {-1, 0}
+};
+#endif
+
+#if 0 /* unused */
+static const int deg_debug_relation_type_color_map[][2] = {
+ {DEPSREL_TYPE_STANDARD, 0},
+ {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
+ {DEPSREL_TYPE_DATABLOCK, 2},
+ {DEPSREL_TYPE_TIME, 3},
+ {DEPSREL_TYPE_COMPONENT_ORDER, 4},
+ {DEPSREL_TYPE_OPERATION, 5},
+ {DEPSREL_TYPE_DRIVER, 6},
+ {DEPSREL_TYPE_DRIVER_TARGET, 7},
+ {DEPSREL_TYPE_TRANSFORM, 8},
+ {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
+ {DEPSREL_TYPE_UPDATE, 10},
+ {DEPSREL_TYPE_UPDATE_UI, 11},
+ {-1, 0}
+};
+#endif
+
+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:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+#if 0
+static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ /* XXX TODO */
+ deg_debug_fprintf(ctx, "" NL);
+}
+
+static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
+ deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
+ deg_debug_fprintf(ctx, "</TABLE></TD>");
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+#endif
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#if 0 /* unused */
+static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
+{
+ const int (*pair)[2];
+ for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+}
+#endif
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+#if 0 /* implementation using stripes, a bit too noisy ... */
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ const char *color_needs_update = "orange";
+ const int num_stripes = 10;
+ int color_index = deg_debug_node_color_index(node);
+ const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ if (ctx.show_tags &&
+ (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE))) {
+ deg_debug_fprintf(ctx, "\"");
+ for (int i = 0; i < num_stripes; ++i) {
+ if (i > 0) {
+ deg_debug_fprintf(ctx, ":");
+ }
+ deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
+ }
+ deg_debug_fprintf(ctx, "\"");
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", base_color);
+ }
+}
+#endif
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *UNUSED(rel))
+{
+ const char *defaultcolor = "black";
+#if 0 /* disabled for now, edge colors are hardly distinguishable */
+ int color = deg_debug_relation_type_color_index(rel->type);
+ if (color < 0) {
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
+ }
+#else
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+#endif
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (id_node->components.empty()) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ deg_debug_graphviz_node_cluster_end(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:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ const DepsNode *op_node = it->second;
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return !id_node->components.empty();
+ }
+ 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:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
+ {
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+#if 0
+ if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
+ const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_ID_REF) {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node_relations(ctx, comp);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
+ }
+ }
+#endif
+}
+
+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);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *node = it->second;
+ deg_debug_graphviz_node(ctx, node);
+ }
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+#if 0
+ if (graph->root_node) {
+ deg_debug_graphviz_node_relations(ctx, graph->root_node);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *id_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, id_node);
+ }
+#else
+ /* XXX not in use yet */
+// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
+// it != graph->all_opnodes.end();
+// ++it)
+// {
+// OperationDepsNode *op_node = *it;
+// deg_debug_graphviz_node_relations(ctx, op_node);
+// }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+#endif
+}
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+#if 0 /* generate shaded color set */
+ static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
+ {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
+ {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
+ int i;
+ const float factor = 0.666f;
+ for (i=0; i < 12; ++i)
+ printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
+#endif
+
+ if (!graph) {
+ return;
+ }
+
+ DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ deg_debug_fprintf(ctx, "graph [");
+ deg_debug_fprintf(ctx, "compound=true");
+ deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ deg_debug_fprintf(ctx, ",splines=ortho");
+ deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ deg_debug_fprintf(ctx, "];" NL);
+
+ deg_debug_graphviz_graph_nodes(ctx, graph);
+ deg_debug_graphviz_graph_relations(ctx, graph);
+
+ deg_debug_graphviz_legend(ctx);
+
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
+
+/* ************************************************ */
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
+ DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next)
+ {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+/* ------------------------------------------------ */
+
+DepsgraphStats *DEG_stats(void)
+{
+ return DepsgraphDebug::stats;
+}
+
+void DEG_stats_verify()
+{
+ DepsgraphDebug::verify_stats();
+}
+
+DepsgraphStatsID *DEG_stats_id(ID *id)
+{
+ if (!DepsgraphDebug::stats) {
+ return NULL;
+ }
+ return DepsgraphDebug::get_id_stats(id, false);
+}
+
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2)
+{
+ BLI_assert(graph1 != NULL);
+ BLI_assert(graph2 != NULL);
+ if (graph1->operations.size() != graph2->operations.size()) {
+ return false;
+ }
+ /* TODO(sergey): Currently we only do real stupid check,
+ * which is fast but which isn't 100% reliable.
+ *
+ * Would be cool to make it more robust, but it's good enough
+ * for now. Also, proper graph check is actually NP-complex
+ * problem..
+ */
+ return true;
+}
+
+bool DEG_debug_scene_relations_validate(Main *bmain,
+ Scene *scene)
+{
+ Depsgraph *depsgraph = DEG_graph_new();
+ bool valid = true;
+ DEG_graph_build_from_scene(depsgraph, bmain, scene);
+ if (!DEG_debug_compare(depsgraph, scene->depsgraph)) {
+ fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
+ BLI_assert(!"This should not happen!");
+ valid = false;
+ }
+ DEG_graph_free(depsgraph);
+ return valid;
+}
+
+bool DEG_debug_consistency_check(Depsgraph *graph)
+{
+ /* Validate links exists in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
+ tmp_rel != node->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
+ tmp_rel != rel->to->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in outgoing direction but not in incoming (%d vs. %d).\n",
+ counter1, counter2);
+ return false;
+ }
+ }
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
+ tmp_rel != node->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
+ tmp_rel != rel->from->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n",
+ counter1, counter2);
+ }
+ }
+ }
+
+ /* Validate node valency calculated in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->num_links_pending = 0;
+ node->done = 0;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ if (node->done) {
+ printf("Node %s is twice in the operations!\n",
+ node->identifier().c_str());
+ return false;
+ }
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->num_links_pending < to->inlinks.size());
+ ++to->num_links_pending;
+ }
+ }
+ node->done = 1;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ int num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ ++num_links_pending;
+ }
+ }
+ if (node->num_links_pending != num_links_pending) {
+ printf("Valency mismatch: %s, %u != %d\n",
+ node->identifier().c_str(),
+ node->num_links_pending, num_links_pending);
+ printf("Number of inlinks: %d\n", (int)node->inlinks.size());
+ return false;
+ }
+ }
+ return true;
+}
+
+/* ------------------------------------------------ */
+
+/**
+ * Obtain simple statistics about the complexity of the depsgraph
+ * \param[out] r_outer The number of outer nodes in the graph
+ * \param[out] r_operations The number of operation nodes in the graph
+ * \param[out] r_relations The number of relations between (executable) nodes in the graph
+ */
+void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
+ size_t *r_operations, size_t *r_relations)
+{
+ /* number of operations */
+ if (r_operations) {
+ /* All operations should be in this list, allowing us to count the total
+ * number of nodes.
+ */
+ *r_operations = graph->operations.size();
+ }
+
+ /* Count number of outer nodes and/or relations between these. */
+ if (r_outer || r_relations) {
+ size_t tot_outer = 0;
+ size_t tot_rels = 0;
+
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ tot_outer++;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ tot_outer++;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ tot_rels += op_node->inlinks.size();
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ tot_rels += time_source->inlinks.size();
+ }
+
+ if (r_relations) *r_relations = tot_rels;
+ if (r_outer) *r_outer = tot_outer;
+ }
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/depsgraph_debug.h
new file mode 100644
index 00000000000..64b97855f57
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.h
@@ -0,0 +1,87 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_debug.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_DEBUG_H__
+#define __DEPSGRAPH_DEBUG_H__
+
+#include "depsgraph_types.h"
+
+extern "C" {
+#include "BKE_global.h"
+}
+
+struct DepsgraphStats;
+struct DepsgraphStatsID;
+struct DepsgraphStatsComponent;
+struct DepsgraphSettings;
+struct EvaluationContext;
+struct OperationDepsNode;
+
+struct Depsgraph;
+
+struct DepsgraphDebug {
+ static DepsgraphStats *stats;
+
+ static void stats_init();
+ static void stats_free();
+
+ static void verify_stats();
+ static void reset_stats();
+
+ static void eval_begin(const EvaluationContext *eval_ctx);
+ static void eval_end(const EvaluationContext *eval_ctx);
+ static void eval_step(const EvaluationContext *eval_ctx,
+ const char *message);
+
+ static void task_started(Depsgraph *graph, const OperationDepsNode *node);
+ static void task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time);
+
+ static DepsgraphStatsID *get_id_stats(ID *id, bool create);
+ static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create);
+ static DepsgraphStatsComponent *get_component_stats(ID *id,
+ const string &name,
+ bool create)
+ {
+ return get_component_stats(get_id_stats(id, create), name, create);
+ }
+};
+
+#define DEG_DEBUG_PRINTF(...) \
+ { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } \
+
+#endif /* __DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
new file mode 100644
index 00000000000..0a1563e7704
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -0,0 +1,394 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_debug.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+static bool use_legacy_depsgraph = true;
+#endif
+
+bool DEG_depsgraph_use_legacy(void)
+{
+#ifdef DISABLE_NEW_DEPSGRAPH
+ return true;
+#elif defined(WITH_LEGACY_DEPSGRAPH)
+ return use_legacy_depsgraph;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+ return false;
+#endif
+}
+
+void DEG_depsgraph_switch_to_legacy(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = true;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+void DEG_depsgraph_switch_to_new(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = false;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+/* ****************** */
+/* Evaluation Context */
+
+/* Create new evaluation context. */
+EvaluationContext *DEG_evaluation_context_new(int mode)
+{
+ EvaluationContext *eval_ctx =
+ (EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
+ "EvaluationContext");
+ eval_ctx->mode = mode;
+ return eval_ctx;
+}
+
+/**
+ * Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(EvaluationContext *eval_ctx, int mode)
+{
+ eval_ctx->mode = mode;
+}
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
+{
+ MEM_freeN(eval_ctx);
+}
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int UNUSED(threadid))
+{
+ DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
+ OperationDepsNode *node = (OperationDepsNode *)taskdata;
+
+ if (!node->is_noop()) {
+ /* Get context. */
+ // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
+ /* TODO(sergey): Wedon't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Take note of current time. */
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+ }
+
+ schedule_children(pool, state->graph, node, state->layers);
+}
+
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const int layers)
+{
+ BLI_spin_lock(&graph->lock);
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) &&
+ node->num_links_pending == 0 &&
+ (id_node->layers & layers) != 0)
+ {
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
+ node->scheduled = true;
+ }
+ }
+ BLI_spin_unlock(&graph->lock);
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers)
+{
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+
+ IDDepsNode *id_child = child->owner->owner;
+ if ((id_child->layers & layers) != 0 &&
+ (child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+
+ if (child->num_links_pending == 0) {
+ BLI_spin_lock(&graph->lock);
+ bool need_schedule = !child->scheduled;
+ child->scheduled = true;
+ BLI_spin_unlock(&graph->lock);
+
+ if (need_schedule) {
+ BLI_task_pool_push(pool, deg_task_run_func, child, false, TASK_PRIORITY_LOW);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = 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);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ calculate_eval_priority(node);
+ }
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ DEG_graph_clear_tags(graph);
+}
+
+/* Evaluate all nodes tagged for updating. */
+void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ Scene *scene)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = BKE_scene_frame_get(scene);
+
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+}
+
+/* Frame-change happened for root scene that graph belongs to. */
+void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
+ Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layers)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = ctime;
+
+ tsrc->tag_update(graph);
+
+ DEG_graph_flush_updates(bmain, graph);
+
+ /* Perform recalculation updates. */
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
new file mode 100644
index 00000000000..7fdc2454564
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -0,0 +1,168 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_intern.h
+ * \ingroup depsgraph
+ *
+ * API's for internal use in the Depsgraph
+ * - Also, defines for "Node Type Info"
+ */
+
+#ifndef __DEPSGRAPH_INTERN_H__
+#define __DEPSGRAPH_INTERN_H__
+
+#include <cstdlib>
+
+#include "MEM_guardedalloc.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+
+struct Main;
+struct Group;
+struct Scene;
+
+/* Graph Building ======================================================== */
+
+/**
+ * Build depsgraph for the given group, and dump results in given graph container
+ * This is usually used for building subgraphs for groups to use...
+ */
+void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
+
+/* Build subgraph for group */
+DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
+
+/* Graph Copying ========================================================= */
+/* (Part of the Filtering API) */
+
+/**
+ * Depsgraph Copying Context (dcc)
+ *
+ * Keeps track of node relationships/links/etc. during the copy
+ * operation so that they can be safely remapped...
+ */
+typedef struct DepsgraphCopyContext {
+ struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
+ struct GHash *rels_hash; // XXX: same for relationships?
+
+ // XXX: filtering criteria...
+} DepsgraphCopyContext;
+
+/* Internal Filtering API ---------------------------------------------- */
+
+/* Create filtering context */
+// XXX: needs params for conditions?
+DepsgraphCopyContext *DEG_filter_init(void);
+
+/* Free filtering context once filtering is done */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
+
+
+/* Data Copy Operations ------------------------------------------------ */
+
+/**
+ * Make a (deep) copy of provided node and it's little subgraph
+ * \warning Newly created node is not added to the existing graph
+ * \param dcc: Context info for helping resolve links
+ */
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+
+/* Node Types Handling ================================================= */
+
+/* "Typeinfo" for Node Types ------------------------------------------- */
+
+/* Typeinfo Struct (nti) */
+struct DepsNodeFactory {
+ virtual eDepsNode_Type type() const = 0;
+ virtual eDepsNode_Class tclass() const = 0;
+ virtual const char *tname() const = 0;
+
+ virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+};
+
+template <class NodeType>
+struct DepsNodeFactoryImpl : public DepsNodeFactory {
+ eDepsNode_Type type() const { return NodeType::typeinfo.type; }
+ eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
+ const char *tname() const { return NodeType::typeinfo.tname; }
+
+ DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
+ {
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+
+ if (!name.empty())
+ /* set name if provided ... */
+ node->name = name;
+ else
+ /* ... otherwise use default type name */
+ node->name = tname();
+
+ node->init(id, subdata);
+
+ return node;
+ }
+
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
+ {
+ BLI_assert(copy->type == type());
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+ // XXX: need to review the name here, as we can't have exact duplicates...
+ node->name = copy->name;
+
+ node->copy(dcc, static_cast<const NodeType *>(copy));
+
+ return node;
+ }
+};
+
+/* Typeinfo Management -------------------------------------------------- */
+
+/* Register typeinfo */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+
+/* Editors Integration -------------------------------------------------- */
+
+void deg_editors_id_update(struct Main *bmain, struct ID *id);
+
+void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
+
+#endif /* __DEPSGRAPH_INTERN_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
new file mode 100644
index 00000000000..73193747b93
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -0,0 +1,217 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_main.h"
+
+#include "DEG_depsgraph_query.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ************************* */
+/* Low-Level Graph Traversal */
+
+#if 0
+/* Prepare for graph traversal, by tagging nodes, etc. */
+static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
+{
+ /* go over all nodes, initialising the valence counts */
+ // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
+}
+
+/* Perform a traversal of graph from given starting node (in execution order) */
+// TODO: additional flags for controlling the process?
+void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
+ DEG_FilterPredicate filter, void *filter_data,
+ DEG_NodeOperation op, void *operation_data)
+{
+ DepsgraphQueue *q;
+
+ /* sanity checks */
+ if (ELEM(NULL, graph, start_node, op))
+ return;
+
+ /* add node as starting node to be evaluated, with value of 0 */
+ q = DEG_queue_new();
+
+ start_node->num_links_pending = 0;
+ DEG_queue_push(q, start_node, 0.0f);
+
+ /* while we still have nodes in the queue, grab and work on next one */
+ do {
+ /* grab item at front of queue */
+ // XXX: in practice, we may need to wait until one becomes available...
+ OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
+
+ /* perform operation on node */
+ op(graph, node, operation_data);
+
+ /* schedule up operations which depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
+ {
+ /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
+ // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
+
+ /* only visit node if the filtering function agrees */
+ if ((filter == NULL) || filter(graph, child_node, filter_data)) {
+ /* schedule up node... */
+ child_node->num_links_pending--;
+ DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+ } while (DEG_queue_is_empty(q) == false);
+
+ /* cleanup */
+ DEG_queue_free(q);
+}
+#endif
+
+/* ************************************************************** */
+/* Filtering API - Basically, making a copy of the existing graph */
+
+/* Create filtering context */
+// TODO: allow passing in a number of criteria?
+DepsgraphCopyContext *DEG_filter_init()
+{
+ DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
+
+ /* init hashes for easy lookups */
+ dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
+ dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
+
+ /* store filtering criteria? */
+ // xxx...
+
+ return dcc;
+}
+
+/* Cleanup filtering context */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
+{
+ /* sanity check */
+ if (dcc == NULL)
+ return;
+
+ /* free hashes - contents are weren't copied, so are ok... */
+ BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
+ BLI_ghash_free(dcc->rels_hash, NULL, NULL);
+
+ /* clear filtering criteria */
+ // ...
+
+ /* free dcc itself */
+ MEM_freeN(dcc);
+}
+
+/* -------------------------------------------------- */
+
+/* Create a copy of provided node */
+// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
+// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
+{
+ /* sanity check */
+ if (src == NULL)
+ return NULL;
+
+ DepsNodeFactory *factory = DEG_get_node_factory(src->type);
+ BLI_assert(factory != NULL);
+ DepsNode *dst = factory->copy_node(dcc, src);
+
+ /* add this node-pair to the hash... */
+ BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
+
+#if 0 /* XXX TODO */
+ /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
+ * all others are derived from) that are now corrupt
+ */
+ {
+ /* relationships to other nodes... */
+ // FIXME: how to handle links? We may only have partial set of all nodes still?
+ // XXX: the exact details of how to handle this are really part of the querying API...
+
+ // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
+ // (i.e. for resolving and patching over links that exist within subtree...)
+ dst->inlinks.clear();
+ dst->outlinks.clear();
+
+ /* clear traversal data */
+ dst->num_links_pending = 0;
+ dst->lasttime = 0;
+ }
+
+ /* fix links */
+ // XXX...
+#endif
+
+ /* return copied node */
+ return dst;
+}
+
+bool DEG_id_type_tagged(Main *bmain, short idtype)
+{
+ return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
+}
+
+short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
+{
+ if (graph == NULL) {
+ /* Happens when converting objects to mesh from a python script
+ * after modifying scene graph.
+ *
+ * Currently harmless because it's only called for temporary
+ * objects which are out of the DAG anyway.
+ */
+ return 0;
+ }
+
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ /* TODO(sergey): Does it mean we need to check set scene? */
+ return 0;
+ }
+
+ return id_node->eval_flags;
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
new file mode 100644
index 00000000000..da60d73bc46
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.cc
@@ -0,0 +1,177 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_queue.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of special queue type for use in Depsgraph traversals.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_heap.h"
+#include "BLI_ghash.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+
+/* ****************************** */
+/* Depsgraph Queue implementation */
+
+/* Data Management ----------------------------------------- */
+
+DepsgraphQueue *DEG_queue_new(void)
+{
+ DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
+
+ /* init data structures for use here */
+ q->pending_heap = BLI_heap_new();
+ q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
+
+ q->ready_heap = BLI_heap_new();
+
+ /* init settings */
+ q->idx = 0;
+ q->tot = 0;
+
+ /* return queue */
+ return q;
+}
+
+void DEG_queue_free(DepsgraphQueue *q)
+{
+ /* free data structures */
+ BLI_assert(BLI_heap_size(q->pending_heap) == 0);
+ BLI_assert(BLI_heap_size(q->ready_heap) == 0);
+ BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
+
+ BLI_heap_free(q->pending_heap, NULL);
+ BLI_heap_free(q->ready_heap, NULL);
+ BLI_ghash_free(q->pending_hash, NULL, NULL);
+
+ /* free queue itself */
+ MEM_freeN(q);
+}
+
+/* Statistics --------------------------------------------- */
+
+/* Get the number of nodes which are we should visit, but are not able to yet */
+size_t DEG_queue_num_pending(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->pending_heap);
+}
+
+/* Get the number of nodes which are now ready to be visited */
+size_t DEG_queue_num_ready(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->ready_heap);
+}
+
+/* Get total size of queue */
+size_t DEG_queue_size(DepsgraphQueue *q)
+{
+ return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
+}
+
+/* Check if queue has any items in it (still passing through) */
+bool DEG_queue_is_empty(DepsgraphQueue *q)
+{
+ return DEG_queue_size(q) == 0;
+}
+
+/* Queue Operations --------------------------------------- */
+
+/**
+ * Add DepsNode to the queue
+ * \param dnode: ``(DepsNode *)`` node to add to the queue
+ * Each node is only added once to the queue; Subsequent pushes
+ * merely update its status (e.g. moving it from "pending" to "ready")
+ * \param cost: new "num_links_pending" count for node *after* it has encountered
+ * via an outlink from the node currently being visited
+ * (i.e. we're one of the dependencies which may now be able to be processed)
+ */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
+{
+ HeapNode *hnode = NULL;
+
+ /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
+ if (cost == 0) {
+ /* node is now ready to be visited - schedule it up for such */
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* remove from pending queue - we're moving it to the scheduling queue */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+
+ BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
+ }
+
+ /* schedule up node using latest count (of ready nodes) */
+ BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
+ q->idx++;
+ }
+ else {
+ /* node is still waiting on some other ancestors,
+ * so add it to the pending heap in the meantime...
+ */
+ // XXX: is this even necessary now?
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* just update cost on pending node */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+ BLI_heap_insert(q->pending_heap, cost, hnode);
+ }
+ else {
+ /* add new node to pending queue, and increase size of overall queue */
+ hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
+ q->tot++;
+ }
+ }
+}
+
+/* Grab a "ready" node from the queue */
+void *DEG_queue_pop(DepsgraphQueue *q)
+{
+ /* sanity check: if there are no "ready" nodes,
+ * start pulling from "pending" to keep things moving,
+ * but throw a warning so that we know that something's up here...
+ */
+ if (BLI_heap_is_empty(q->ready_heap)) {
+ // XXX: this should never happen
+ // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
+ printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
+ (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
+
+ return BLI_heap_popmin(q->pending_heap);
+ }
+ else {
+ /* only grab "ready" nodes */
+ return BLI_heap_popmin(q->ready_heap);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
new file mode 100644
index 00000000000..b85d46bd173
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.h
@@ -0,0 +1,91 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_queue.h
+ * \ingroup depsgraph
+ *
+ * Defines for special queue type for use in Depsgraph traversals.
+ */
+
+#ifndef __DEPSGRAPH_QUEUE_H__
+#define __DEPSGRAPH_QUEUE_H__
+
+struct DepsNode;
+
+struct Heap;
+struct GHash;
+
+/* *********************************************** */
+/* Dependency Graph Traversal Queue
+ *
+ * There are two parts to this:
+ * a) "Pending" Nodes - This part contains the set of nodes
+ * which are related to those which have been visited
+ * previously, but are not yet ready to actually be visited.
+ * b) "Scheduled" Nodes - These are the nodes whose ancestors
+ * have all been evaluated already, which means that any
+ * or all of them can be picked (in practically in order) to
+ * be visited immediately.
+ *
+ * Internally, the queue makes sure that each node in the graph
+ * only gets added to the queue once. This is because there can
+ * be multiple inlinks to each node given the way that the relations
+ * work.
+ */
+
+/* Depsgraph Queue Type */
+typedef struct DepsgraphQueue {
+ /* Pending */
+ struct Heap *pending_heap; /* (valence:int, DepsNode*) */
+ struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
+
+ /* Ready to be visited - fifo */
+ struct Heap *ready_heap; /* (idx:int, DepsNode*) */
+
+ /* Size/Order counts */
+ size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
+ size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
+} DepsgraphQueue;
+
+/* ************************** */
+/* Depsgraph Queue Operations */
+
+/* Data management */
+DepsgraphQueue *DEG_queue_new(void);
+void DEG_queue_free(DepsgraphQueue *q);
+
+/* Statistics */
+size_t DEG_queue_num_pending(DepsgraphQueue *q);
+size_t DEG_queue_num_ready(DepsgraphQueue *q);
+
+size_t DEG_queue_size(DepsgraphQueue *q);
+bool DEG_queue_is_empty(DepsgraphQueue *q);
+
+/* Operations */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
+void *DEG_queue_pop(DepsgraphQueue *q);
+
+#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
new file mode 100644
index 00000000000..65d75fccad3
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -0,0 +1,541 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_tag.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include <stdio.h>
+#include <cstring>
+#include <queue>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+
+#define new new_
+#include "BKE_screen.h"
+#undef new
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********************** */
+/* Update Tagging/Flushing */
+
+/* Legacy depsgraph did some special trickery for things like particle systems
+ * when tagging ID for an update. Ideally that tagging needs to become obsolete
+ * in favor of havng dedicated node for that which gets tagged, but for until
+ * design of those areas is more clear we'll do the same legacy code here.
+ * - sergey -
+ */
+#define DEPSGRAPH_USE_LEGACY_TAGGING
+
+namespace {
+
+/* Data-Based Tagging ------------------------------- */
+
+void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
+{
+ if (flag) {
+ /* This bit of code ensures legacy object->recalc flags
+ * are still filled in the same way as it was expected
+ * with the old dependency graph.
+ *
+ * This is because some areas like motion paths and likely
+ * some other physics baking process are doing manual scene
+ * update on all the frames, trying to minimize number of
+ * updates.
+ *
+ * But this flag will also let us to re-construct entry
+ * nodes for update after relations update and after layer
+ * visibility changes.
+ */
+ short idtype = GS(id->name);
+ if (idtype == ID_OB) {
+ Object *object = (Object *)id;
+ object->recalc |= (flag & OB_RECALC_ALL);
+ }
+
+ if (flag & OB_RECALC_OB)
+ lib_id_recalc_tag(bmain, id);
+ if (flag & (OB_RECALC_DATA | PSYS_RECALC))
+ lib_id_recalc_data_tag(bmain, id);
+ }
+ else {
+ lib_id_recalc_tag(bmain, id);
+ }
+}
+
+#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
+void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
+{
+ if (flag) {
+ Object *object;
+ short idtype = GS(id->name);
+ if (idtype == ID_PA) {
+ ParticleSystem *psys;
+ for (object = (Object *)bmain->object.first;
+ object != NULL;
+ object = (Object *)object->id.next)
+ {
+ for (psys = (ParticleSystem *)object->particlesystem.first;
+ psys != NULL;
+ psys = (ParticleSystem *)psys->next)
+ {
+ if (&psys->part->id == id) {
+ DEG_id_tag_update_ex(bmain, &object->id, flag & OB_RECALC_ALL);
+ psys->recalc |= (flag & PSYS_RECALC);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+} /* namespace */
+
+/* Tag all nodes in ID-block for update.
+ * This is a crude measure, but is most convenient for old code.
+ */
+void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
+{
+ IDDepsNode *node = graph->find_id_node(id);
+ lib_id_recalc_tag(bmain, id);
+ if (node != NULL) {
+ node->tag_update(graph);
+ }
+}
+
+/* Tag nodes related to a specific piece of data */
+void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag nodes related to a specific property. */
+void DEG_graph_property_tag_update(Depsgraph *graph,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, prop);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ if (id == NULL) {
+ /* Ideally should not happen, but old depsgraph allowed this. */
+ return;
+ }
+ DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
+ lib_id_recalc_tag_flag(bmain, id, flag);
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph) {
+ Depsgraph *graph = scene->depsgraph;
+ if (flag == 0) {
+ /* TODO(sergey): Currently blender is still tagging IDs
+ * for recalc just using flag=0. This isn't totally correct
+ * but we'd better deal with such cases and don't fail.
+ */
+ DEG_graph_id_tag_update(bmain, graph, id);
+ continue;
+ }
+ if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->data != NULL) {
+ DEG_graph_id_tag_update(bmain,
+ graph,
+ (ID *)object->data);
+ }
+ }
+ if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
+ DEG_graph_id_tag_update(bmain, graph, id);
+ }
+ }
+ }
+
+#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
+ /* Special handling from the legacy depsgraph.
+ * TODO(sergey): Need to get rid of those once all the areas
+ * are re-formulated in terms of franular nodes.
+ */
+ depsgraph_legacy_handle_update_tag(bmain, id, flag);
+#endif
+}
+
+/* Tag given ID type for update. */
+void DEG_id_type_tag(Main *bmain, short idtype)
+{
+ if (idtype == ID_NT) {
+ /* Stupid workaround so parent datablocks of nested nodetree get looped
+ * over when we loop over tagged datablock types.
+ */
+ DEG_id_type_tag(bmain, ID_MA);
+ DEG_id_type_tag(bmain, ID_TE);
+ DEG_id_type_tag(bmain, ID_LA);
+ DEG_id_type_tag(bmain, ID_WO);
+ DEG_id_type_tag(bmain, ID_SCE);
+ }
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
+}
+
+/* Update Flushing ---------------------------------- */
+
+/* FIFO queue for tagged nodes that need flushing */
+/* XXX This may get a dedicated implementation later if needed - lukas */
+typedef std::queue<OperationDepsNode *> FlushQueue;
+
+/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
+void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* sanity check */
+ if (graph == NULL)
+ return;
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->scheduled = false;
+ }
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
+ it != graph->entry_tags.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ queue.push(node);
+ deg_editors_id_update(bmain, id_node->id);
+ node->scheduled = true;
+ }
+
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop();
+
+ IDDepsNode *id_node = node->owner->owner;
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ ID *id = id_node->id;
+ /* This code is used to preserve those areas which does direct
+ * object update,
+ *
+ * Plus it ensures visibility changes and relations and layers
+ * visibility update has proper flags to work with.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ComponentDepsNode *comp_node = node->owner;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ /* Flush to nodes along links... */
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ queue.push(to_node);
+ to_node->scheduled = true;
+ deg_editors_id_update(bmain, id_node->id);
+ }
+ }
+
+ /* TODO(sergey): For until incremental updates are possible
+ * witin a component at least we tag the whole component
+ * for update.
+ */
+ for (ComponentDepsNode::OperationMap::iterator it = node->owner->operations.begin();
+ it != node->owner->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op = it->second;
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ }
+}
+
+/* Recursively push updates out to all nodes dependent on this,
+ * until all affected are tagged and/or scheduled up for eval
+ */
+void DEG_ids_flush_tagged(Main *bmain)
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ /* TODO(sergey): Only visible scenes? */
+ if (scene->depsgraph != NULL) {
+ DEG_graph_flush_updates(bmain, scene->depsgraph);
+ }
+ }
+}
+
+/* Clear tags from all operation nodes. */
+void DEG_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+ /* Reset so that it can be bumped up again. */
+ node->num_links_pending = 0;
+ node->scheduled = false;
+ }
+
+ /* Clear any entry tags which haven't been flushed. */
+ graph->entry_tags.clear();
+}
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
+{
+ Depsgraph *graph = scene->depsgraph;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ int old_layers = graph->layers;
+ if (wm != NULL) {
+ BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, true);
+ graph->layers = 0;
+ for (wmWindow *win = (wmWindow *)wm->windows.first;
+ win != NULL;
+ win = (wmWindow *)win->next)
+ {
+ Scene *scene = win->screen->scene;
+ if (scene->id.flag & LIB_DOIT) {
+ graph->layers |= BKE_screen_visible_layers(win->screen, scene);
+ scene->id.flag &= ~LIB_DOIT;
+ }
+ }
+ }
+ else {
+ /* All the layers for background render for now. */
+ graph->layers = (1 << 20) - 1;
+ }
+ if (old_layers != graph->layers) {
+ /* Tag all objects which becomes visible (or which becomes needed for dependencies)
+ * for recalc.
+ *
+ * This is mainly needed on file load only, after that updates of invisible objects
+ * will be stored in the pending list.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if ((id->flag & LIB_ID_RECALC_ALL) != 0 ||
+ (id_node->layers & scene->lay_updated) == 0)
+ {
+ id_node->tag_update(graph);
+ }
+ /* A bit of magic: if object->recalc is set it means somebody tagged
+ * it for update. If corresponding ID recalc flags are zero it means
+ * graph has been evaluated after that and the recalc was skipped
+ * because of visibility check.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if ((id->flag & LIB_ID_RECALC_ALL) == 0 &&
+ (object->recalc & OB_RECALC_ALL) != 0)
+ {
+ id_node->tag_update(graph);
+ ComponentDepsNode *anim_comp =
+ id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
+ anim_comp->tag_update(graph);
+ }
+ }
+ }
+ }
+ }
+ scene->lay_updated |= graph->layers;
+}
+
+void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_on_visible_update(bmain, scene);
+ }
+ }
+}
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool updated = false;
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID *)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ updated = true;
+ break;
+ }
+ }
+
+ deg_editors_scene_update(bmain, scene, (updated || time));
+}
+
+void DEG_ids_clear_recalc(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ bNodeTree *ntree;
+ int a;
+
+ /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
+ * and id_tags storage from the new dependency graph.
+ */
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID *)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ for (; id; id = (ID *)id->next) {
+ id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+
+ /* Some ID's contain semi-datablock nodetree */
+ ntree = ntreeFromID(id);
+ if (ntree != NULL) {
+ ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ }
+ }
+ }
+ }
+
+ memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
new file mode 100644
index 00000000000..5a3048a4aa3
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -0,0 +1,102 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_type_defines.cc
+ * \ingroup depsgraph
+ *
+ * Defines and code for core node types.
+ */
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_intern.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* ************ */
+/* External API */
+
+/* Global type registry */
+
+/**
+ * \note For now, this is a hashtable not array, since the core node types
+ * currently do not have contiguous ID values. Using a hash here gives us
+ * more flexibility, albeit using more memory and also sacrificing a little
+ * speed. Later on, when things stabilise we may turn this back to an array
+ * since there are only just a few node types that an array would cope fine...
+ */
+static GHash *_depsnode_typeinfo_registry = NULL;
+
+/* Registration ------------------------------------------- */
+
+/* Register node type */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+{
+ BLI_assert(factory != NULL);
+ BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
+}
+
+/* Register all node types */
+void DEG_register_node_types(void)
+{
+ /* initialise registry */
+ _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+
+ /* register node types */
+ DEG_register_base_depsnodes();
+ DEG_register_component_depsnodes();
+ DEG_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
+}
+
+/* Getters ------------------------------------------------- */
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+{
+ /* look up type - at worst, it doesn't exist in table yet, and we fail */
+ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+}
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+{
+ if (!node)
+ return NULL;
+
+ return DEG_get_node_factory(node->type);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
new file mode 100644
index 00000000000..3616fe85496
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -0,0 +1,173 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_types.h
+ * \ingroup depsgraph
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_TYPES_H__
+#define __DEPSGRAPH_TYPES_H__
+
+#include "depsgraph_util_function.h"
+
+/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
+ * to avoid any possible overhead caused by string (re)allocation/formatting.
+ */
+#include <string>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+struct bAction;
+struct ChannelDriver;
+struct ModifierData;
+struct PointerRNA;
+struct EvaluationContext;
+struct FCurve;
+
+/* Evaluation Operation for atomic operation */
+// XXX: move this to another header that can be exposed?
+typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
+
+/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+typedef enum eDepsNode_Class {
+ DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
+
+ DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
+ DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+} eDepsNode_Class;
+
+/* Types of Nodes */
+typedef enum eDepsNode_Type {
+ DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+
+ DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+
+ /* Generic Types */
+ DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
+ DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+
+ DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
+ DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+
+ /* Outer Types */
+ DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
+ DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
+ DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
+} eDepsNode_Type;
+
+/* Identifiers for common operations (as an enum) */
+typedef enum eDepsOperation_Code {
+#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+} eDepsOperation_Code;
+
+/* String defines for these opcodes, defined in depsnode_operation.cpp */
+extern const char *DEG_OPNAMES[];
+
+
+/* Type of operation */
+typedef enum eDepsOperation_Type {
+ /* Primary operation types */
+ DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
+ DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
+ DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
+
+ /* Additional operation types */
+ DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
+ DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
+ DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+} 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 {
+ /* reationship 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,
+} eDepsRelation_Type;
+
+#endif /* __DEPSGRAPH_TYPES_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/depsnode.cc
new file mode 100644
index 00000000000..1736aadf999
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.cc
@@ -0,0 +1,316 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode.cc
+ * \ingroup depsgraph
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+
+#include "DEG_depsgraph.h"
+}
+
+#include "depsnode.h" /* own include */
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *************** */
+/* Node Management */
+
+/* Add ------------------------------------------------ */
+
+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;
+ else
+ this->tclass = DEPSNODE_CLASS_COMPONENT;
+ this->tname = tname;
+}
+
+DepsNode::DepsNode()
+{
+ this->name[0] = '\0';
+}
+
+DepsNode::~DepsNode()
+{
+ /* free links
+ * note: deleting relations will remove them from the node relations set,
+ * but only touch the same position as we are using here, which is safe.
+ */
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->outlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+}
+
+
+/* Generic identifier for Depsgraph Nodes. */
+string DepsNode::identifier() const
+{
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + " : " + name;
+}
+
+/* ************* */
+/* Generic Nodes */
+
+/* Time Source Node ============================================== */
+
+void TimeSourceDepsNode::tag_update(Depsgraph *graph)
+{
+ for (DepsNode::Relations::const_iterator it = outlinks.begin();
+ it != outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ DepsNode *node = rel->to;
+ node->tag_update(graph);
+ }
+}
+
+
+/* Root Node ============================================== */
+
+RootDepsNode::RootDepsNode() : scene(NULL), time_source(NULL)
+{
+}
+
+RootDepsNode::~RootDepsNode()
+{
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
+}
+
+TimeSourceDepsNode *RootDepsNode::add_time_source(const string &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");
+static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
+
+/* ID Node ================================================ */
+
+/* Initialize 'id' node - from pointer data given. */
+void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
+{
+ /* Store ID-pointer. */
+ BLI_assert(id != NULL);
+ this->id = (ID *)id;
+ this->layers = (1 << 20) - 1;
+ this->eval_flags = 0;
+
+ /* NOTE: components themselves are created if/when needed.
+ * This prevents problems with components getting added
+ * twice if an ID-Ref needs to be created to house it...
+ */
+}
+
+/* Free 'id' node. */
+IDDepsNode::~IDDepsNode()
+{
+ clear_components();
+}
+
+/* Copy 'id' node. */
+void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
+{
+ (void)src; /* Ignored. */
+ /* Iterate over items in original hash, adding them to new hash. */
+ for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
+ it != this->components.end();
+ ++it)
+ {
+ /* Get current <type : component> mapping. */
+ ComponentIDKey c_key = it->first;
+ DepsNode *old_component = it->second;
+
+ /* Make a copy of component. */
+ ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
+
+ /* Add new node to hash... */
+ this->components[c_key] = component;
+ }
+
+ // TODO: perform a second loop to fix up links?
+ BLI_assert(!"Not expected to be used");
+}
+
+ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
+ const string &name) const
+{
+ ComponentIDKey key(type, name);
+ ComponentMap::const_iterator it = components.find(key);
+ return it != components.end() ? it->second : NULL;
+}
+
+ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
+ const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (!comp_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
+
+ /* Register. */
+ this->components[key] = comp_node;
+ comp_node->owner = this;
+ }
+ return comp_node;
+}
+
+void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (comp_node) {
+ /* Unregister. */
+ this->components.erase(key);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+}
+
+void IDDepsNode::clear_components()
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+ components.clear();
+}
+
+void IDDepsNode::tag_update(Depsgraph *graph)
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ /* TODO(sergey): What about drievrs? */
+ bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ BLI_assert(adt != NULL);
+ if (adt->recalc & ADT_RECALC_ANIM) {
+ do_component_tag = true;
+ }
+ }
+ if (do_component_tag) {
+ comp_node->tag_update(graph);
+ }
+ }
+}
+
+DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_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 string &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(this->graph);
+ this->graph = NULL;
+ }
+}
+
+/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
+void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const SubgraphDepsNode * /*src*/)
+{
+ //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
+ //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
+
+ /* for now, subgraph itself isn't copied... */
+ BLI_assert(!"Not expected to be used");
+}
+
+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);
+}
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/depsnode.h
new file mode 100644
index 00000000000..53826ae8e71
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.h
@@ -0,0 +1,248 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_H__
+#define __DEPSNODE_H__
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct Scene;
+
+struct Depsgraph;
+struct DepsRelation;
+struct DepsgraphCopyContext;
+struct OperationDepsNode;
+
+/* *********************************** */
+/* Base-Defines for Nodes in Depsgraph */
+
+/* All nodes in Depsgraph are descended from this. */
+struct DepsNode {
+ /* Helper class for static typeinfo in subclasses. */
+ struct TypeInfo {
+ TypeInfo(eDepsNode_Type type, const char *tname);
+
+ eDepsNode_Type type;
+ eDepsNode_Class tclass;
+ const char *tname;
+ };
+
+ /* Identifier - mainly for debugging purposes. */
+ string name;
+
+ /* Structural type of node. */
+ eDepsNode_Type type;
+
+ /* Type of data/behaviour represented by node... */
+ eDepsNode_Class tclass;
+
+ /* Relationships between nodes
+ * The reason why all depsgraph nodes are descended from this type (apart
+ * from basic serialization benefits - from the typeinfo) is that we can have
+ * relationships between these nodes!
+ */
+ typedef unordered_set<DepsRelation *> Relations;
+
+ /* Nodes which this one depends on. */
+ Relations inlinks;
+
+ /* Nodes which depend on this one. */
+ Relations outlinks;
+
+ /* Generic tag for traversal algorithms */
+ int done;
+
+ /* Methods. */
+
+ DepsNode();
+ virtual ~DepsNode();
+
+ virtual string identifier() const;
+ string full_identifier() const;
+
+ virtual void init(const ID * /*id*/,
+ const string &/*subdata*/) {}
+ virtual void copy(DepsgraphCopyContext * /*dcc*/,
+ const DepsNode * /*src*/) {}
+
+ virtual void tag_update(Depsgraph * /*graph*/) {}
+
+ virtual OperationDepsNode *get_entry_operation() { return NULL; }
+ virtual OperationDepsNode *get_exit_operation() { return NULL; }
+};
+
+/* Macros for common static typeinfo. */
+#define DEG_DEPSNODE_DECLARE \
+ static const DepsNode::TypeInfo typeinfo
+#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
+ const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_)
+
+/* Generic Nodes ======================= */
+
+struct ComponentDepsNode;
+struct IDDepsNode;
+
+/* Time Source Node. */
+struct TimeSourceDepsNode : public DepsNode {
+ /* New "current time". */
+ float cfra;
+
+ /* time-offset relative to the "official" time source that this one has. */
+ float offset;
+
+ // TODO: evaluate() operation needed
+
+ void tag_update(Depsgraph *graph);
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Root Node. */
+struct RootDepsNode : public DepsNode {
+ RootDepsNode();
+ ~RootDepsNode();
+
+ TimeSourceDepsNode *add_time_source(const string &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 {
+ ComponentIDKey(eDepsNode_Type type, const string &name = "")
+ : type(type), name(name) {}
+
+ bool operator== (const ComponentIDKey &other) const
+ {
+ return type == other.type && name == other.name;
+ }
+
+ eDepsNode_Type type;
+ string name;
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
+ * a nested type ...
+ *
+ * http://stackoverflow.com/a/951245
+ */
+ struct component_key_hash {
+ bool operator() (const ComponentIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
+ }
+ };
+
+ typedef unordered_map<ComponentIDKey,
+ ComponentDepsNode *,
+ component_key_hash> ComponentMap;
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
+ ~IDDepsNode();
+
+ ComponentDepsNode *find_component(eDepsNode_Type type,
+ const string &name = "") const;
+ ComponentDepsNode *add_component(eDepsNode_Type type,
+ const string &name = "");
+ void remove_component(eDepsNode_Type type, const string &name = "");
+ void clear_components();
+
+ void tag_update(Depsgraph *graph);
+
+ /* ID Block referenced. */
+ ID *id;
+
+ /* Hash to make it faster to look up components. */
+ ComponentMap components;
+
+ /* Layers of this node with accumulated layers of it's output relations. */
+ int layers;
+
+ /* Additional flags needed for scene evaluation.
+ * TODO(sergey): Only needed for until really granular updates
+ * of all the entities.
+ */
+ int eval_flags;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Subgraph Reference. */
+struct SubgraphDepsNode : public DepsNode {
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
+ ~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();
+
+#endif /* __DEPSNODE_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/depsnode_component.cc
new file mode 100644
index 00000000000..1d939c6580d
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.cc
@@ -0,0 +1,318 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_component.cc
+ * \ingroup depsgraph
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+} /* extern "C" */
+
+#include "depsnode_component.h" /* own include */
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********** */
+/* Outer Nodes */
+
+/* Standard Component Methods ============================= */
+
+ComponentDepsNode::ComponentDepsNode() :
+ entry_operation(NULL),
+ exit_operation(NULL)
+{
+}
+
+/* Initialize 'component' node - from pointer data given */
+void ComponentDepsNode::init(const ID * /*id*/,
+ const string & /*subdata*/)
+{
+ /* hook up eval context? */
+ // XXX: maybe this needs a special API?
+}
+
+/* Copy 'component' node */
+void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const ComponentDepsNode * /*src*/)
+{
+#if 0 // XXX: remove all this
+ /* duplicate list of operation nodes */
+ this->operations.clear();
+
+ for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
+ const string &pchan_name = it->first;
+ OperationDepsNode *src_op = it->second;
+
+ /* recursive copy */
+ DepsNodeFactory *factory = DEG_node_get_factory(src_op);
+ OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
+ this->operations[pchan_name] = dst_op;
+
+ /* fix links... */
+ // ...
+ }
+
+ /* copy evaluation contexts */
+ //
+#endif
+ BLI_assert(!"Not expected to be called");
+}
+
+/* Free 'component' node */
+ComponentDepsNode::~ComponentDepsNode()
+{
+ clear_operations();
+}
+
+string ComponentDepsNode::identifier() const
+{
+ string &idname = this->owner->name;
+
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + name + " : " + idname;
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ else {
+ fprintf(stderr, "%s: find_operation(%s) failed\n",
+ this->identifier().c_str(), key.identifier().c_str());
+ BLI_assert(!"Request for non-existing operation, should not happen");
+ return NULL;
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return find_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
+ const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return has_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = has_operation(opcode, name);
+ if (!op_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
+
+ /* register opnode in this component's operation set */
+ OperationIDKey key(opcode, name);
+ this->operations[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;
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ this->identifier().c_str(), op_node->identifier().c_str(), op_node);
+ BLI_assert(!"Should not happen!");
+ }
+
+ /* attach extra data */
+ op_node->evaluate = op;
+ op_node->optype = optype;
+ op_node->opcode = opcode;
+ op_node->name = name;
+
+ return op_node;
+}
+
+void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = find_operation(opcode, name);
+ if (op_node) {
+ /* unregister */
+ this->operations.erase(OperationIDKey(opcode, name));
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+}
+
+void ComponentDepsNode::clear_operations()
+{
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+ operations.clear();
+}
+
+void ComponentDepsNode::tag_update(Depsgraph *graph)
+{
+ OperationDepsNode *entry_op = get_entry_operation();
+ if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ op_node->tag_update(graph);
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::get_entry_operation()
+{
+ if (entry_operation)
+ return entry_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::get_exit_operation()
+{
+ if (exit_operation)
+ return exit_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+/* Parameter Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
+static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
+
+/* Animation Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
+static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
+
+/* Transform Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
+static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
+
+/* Proxy Component Defines ================================ */
+
+DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
+static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
+
+/* Geometry Component Defines ============================= */
+
+DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
+static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
+
+/* Sequencer Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
+static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
+
+/* Pose Component ========================================= */
+
+DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
+static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
+
+/* Bone Component ========================================= */
+
+/* Initialize 'bone component' node - from pointer data given */
+void BoneComponentDepsNode::init(const ID *id, const string &subdata)
+{
+ /* generic component-node... */
+ ComponentDepsNode::init(id, subdata);
+
+ /* name of component comes is bone name */
+ /* TODO(sergey): This sets name to an empty string because subdata is
+ * empty. Is it a bug?
+ */
+ //this->name = subdata;
+
+ /* bone-specific node data */
+ Object *ob = (Object *)id;
+ this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
+}
+
+DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
+static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
+
+/* Particles Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
+static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
+
+/* Shading Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
+static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
+
+
+/* Node Types Register =================================== */
+
+void DEG_register_component_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_PARAMETERS);
+ DEG_register_node_typeinfo(&DNTI_PROXY);
+ DEG_register_node_typeinfo(&DNTI_ANIMATION);
+ DEG_register_node_typeinfo(&DNTI_TRANSFORM);
+ DEG_register_node_typeinfo(&DNTI_GEOMETRY);
+ DEG_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
+ DEG_register_node_typeinfo(&DNTI_BONE);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ DEG_register_node_typeinfo(&DNTI_SHADING);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/depsnode_component.h
new file mode 100644
index 00000000000..e3550bb2371
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.h
@@ -0,0 +1,201 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_component.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_COMPONENT_H__
+#define __DEPSNODE_COMPONENT_H__
+
+#include "depsnode.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct bPoseChannel;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+struct EvaluationContext;
+struct OperationDepsNode;
+struct BoneComponentDepsNode;
+
+
+/* ID Component - Base type for all components */
+struct ComponentDepsNode : public DepsNode {
+ /* Key used to look up operations within a component */
+ struct OperationIDKey
+ {
+ eDepsOperation_Code opcode;
+ string name;
+
+
+ OperationIDKey() :
+ opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode) :
+ opcode(opcode), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode, const string &name) :
+ opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char codebuf[5];
+ sprintf(codebuf, "%d", opcode);
+
+ return string("OperationIDKey(") + codebuf + ", " + name + ")";
+ }
+
+ bool operator==(const OperationIDKey &other) const
+ {
+ return (opcode == other.opcode) && (name == other.name);
+ }
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
+ * http://stackoverflow.com/a/951245
+ */
+ struct operation_key_hash {
+ bool operator() (const OperationIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
+ }
+ };
+
+ /* Typedef for container of operations */
+ typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
+
+
+ ComponentDepsNode();
+ ~ComponentDepsNode();
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
+
+ string identifier() const;
+
+ /* Find an existing operation, will throw an assert() if it does not exist. */
+ OperationDepsNode *find_operation(OperationIDKey key) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /* Check operation exists and return it. */
+ OperationDepsNode *has_operation(OperationIDKey key) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /**
+ * Create a new node for representing an operation and add this to graph
+ * \warning If an existing node is found, it will be modified. This helps when node may
+ * have been partially created earlier (e.g. parent ref before parent item is added)
+ *
+ * \param type: Operation node type (corresponding to context/component that it operates in)
+ * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \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, eDepsOperation_Code opcode, const string &name);
+
+ void remove_operation(eDepsOperation_Code opcode, const string &name);
+ void clear_operations();
+
+ void tag_update(Depsgraph *graph);
+
+ /* Evaluation Context Management .................. */
+
+ /* Initialize component's evaluation context used for the specified purpose */
+ virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
+ /* Free data in component's evaluation context which is used for the specified purpose
+ * NOTE: this does not free the actual context in question
+ */
+ virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
+
+ OperationDepsNode *get_entry_operation();
+ OperationDepsNode *get_exit_operation();
+
+ IDDepsNode *owner;
+
+ OperationMap operations; /* inner nodes for this component */
+ OperationDepsNode *entry_operation;
+ OperationDepsNode *exit_operation;
+
+ // XXX: a poll() callback to check if component's first node can be started?
+};
+
+/* ---------------------------------------- */
+
+struct ParametersComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct AnimationComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct TransformComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ProxyComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct GeometryComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct SequencerComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct PoseComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Bone Component */
+struct BoneComponentDepsNode : public ComponentDepsNode {
+ void init(const ID *id, const string &subdata);
+
+ struct bPoseChannel *pchan; /* the bone that this component represents */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ParticlesComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ShadingComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+
+void DEG_register_component_depsnodes();
+
+#endif /* __DEPSNODE_COMPONENT_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
new file mode 100644
index 00000000000..b81822c0ac5
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_opcodes.h
@@ -0,0 +1,145 @@
+/*
+ * ***** 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.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_opcodes.h
+ * \ingroup depsgraph
+ *
+ * \par OpCodes for OperationDepsNodes
+ *
+ * This file defines all the "operation codes" (opcodes) used to identify
+ * common operation node types. The intention of these defines is to have
+ * a fast and reliable way of identifying the relevant nodes within a component
+ * without having to use fragile dynamic strings.
+ *
+ * This file is meant to be used like UI_icons.h. That is, before including
+ * the file, the host file must define the DEG_OPCODE(_label) macro, which
+ * is responsible for converting the define into whatever form is suitable.
+ * Therefore, it intentionally doesn't have header guards.
+ */
+
+
+/* Example macro define: */
+/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
+
+/* Generic Operations ------------------------------ */
+
+/* Placeholder for operations which don't need special mention */
+DEF_DEG_OPCODE(OPERATION)
+
+// XXX: Placeholder while porting depsgraph code
+DEF_DEG_OPCODE(PLACEHOLDER)
+
+DEF_DEG_OPCODE(NOOP)
+
+/* Animation, Drivers, etc. ------------------------ */
+
+/* NLA + Action */
+DEF_DEG_OPCODE(ANIMATION)
+
+/* Driver */
+DEF_DEG_OPCODE(DRIVER)
+
+/* Proxy Inherit? */
+//DEF_DEG_OPCODE(PROXY)
+
+/* Transform --------------------------------------- */
+
+/* Transform entry point - local transforms only */
+DEF_DEG_OPCODE(TRANSFORM_LOCAL)
+
+/* Parenting */
+DEF_DEG_OPCODE(TRANSFORM_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
+
+/* Rigidbody Sim - Perform Sim */
+DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
+DEF_DEG_OPCODE(RIGIDBODY_SIM)
+
+/* Rigidbody Sim - Copy Results to Object */
+DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
+
+/* Transform exitpoint */
+DEF_DEG_OPCODE(TRANSFORM_FINAL)
+
+/* XXX: ubereval is for temporary porting purposes only */
+DEF_DEG_OPCODE(OBJECT_UBEREVAL)
+
+/* Geometry ---------------------------------------- */
+
+/* XXX: Placeholder - UberEval */
+DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
+
+/* Modifier */
+DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
+
+/* Curve Objects - Path Calculation (used for path-following tools) */
+DEF_DEG_OPCODE(GEOMETRY_PATH)
+
+/* Pose -------------------------------------------- */
+
+/* Init IK Trees, etc. */
+DEF_DEG_OPCODE(POSE_INIT)
+
+/* Free IK Trees + Compute Deform Matrices */
+DEF_DEG_OPCODE(POSE_DONE)
+
+/* IK/Spline Solvers */
+DEF_DEG_OPCODE(POSE_IK_SOLVER)
+DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
+
+/* Bone -------------------------------------------- */
+
+/* Bone local transforms - Entrypoint */
+DEF_DEG_OPCODE(BONE_LOCAL)
+
+/* Pose-space conversion (includes parent + restpose) */
+DEF_DEG_OPCODE(BONE_POSE_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(BONE_CONSTRAINTS)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
+
+/* Bone transforms are ready
+ * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
+ * Its role is to help mediate situations where cyclic relations may otherwise form
+ * (i.e. one bone in chain targetting another in same chain)
+ * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
+ */
+// TODO: deform mats could get calculated in the final_transform ops...
+DEF_DEG_OPCODE(BONE_READY)
+DEF_DEG_OPCODE(BONE_DONE)
+
+/* Particles --------------------------------------- */
+
+/* XXX: placeholder - Particle System eval */
+DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/depsnode_operation.cc
new file mode 100644
index 00000000000..6aeb163356b
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.cc
@@ -0,0 +1,104 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_operation.cc
+ * \ingroup depsgraph
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+} /* extern "C" */
+
+#include "depsnode_operation.h" /* own include */
+#include "depsnode_component.h"
+#include "depsgraph.h"
+#include "depsgraph_intern.h"
+
+/* ******************************************************************* */
+/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+
+/* identifiers for operations */
+const char *DEG_OPNAMES[] = {
+#define DEF_DEG_OPCODE(label) #label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+
+ "<Invalid>"
+};
+
+/* *********** */
+/* Inner Nodes */
+
+OperationDepsNode::OperationDepsNode() :
+ eval_priority(0.0f),
+ flag(0)
+{
+}
+
+OperationDepsNode::~OperationDepsNode()
+{
+}
+
+string OperationDepsNode::identifier() const
+{
+ BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
+ return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
+}
+
+/* Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
+string OperationDepsNode::full_identifier() const
+{
+ string owner_str = "";
+ if (owner->type == DEPSNODE_TYPE_BONE) {
+ owner_str = owner->owner->name + "." + owner->name;
+ }
+ else {
+ owner_str = owner->owner->name;
+ }
+ return owner_str + "." + identifier();
+}
+
+void OperationDepsNode::tag_update(Depsgraph *graph)
+{
+ if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ /* Tag for update, but also note that this was the source of an update. */
+ flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
+ graph->add_entry_tag(this);
+}
+
+DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
+static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
+
+void DEG_register_operation_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_OPERATION);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/depsnode_operation.h
new file mode 100644
index 00000000000..1119e10805d
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.h
@@ -0,0 +1,90 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_operation.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_OPERATION_H__
+#define __DEPSNODE_OPERATION_H__
+
+#include "depsnode.h"
+
+struct ID;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+
+/* Flags for Depsgraph Nodes */
+typedef enum eDepsOperation_Flag {
+ /* node needs to be updated */
+ 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 implications... */
+ DEPSOP_FLAG_USES_PYTHON = (1 << 2),
+} eDepsOperation_Flag;
+
+/* Atomic Operation - Base type for all operations */
+struct OperationDepsNode : public DepsNode {
+
+
+ OperationDepsNode();
+ ~OperationDepsNode();
+
+ string identifier() const;
+ string full_identifier() const;
+
+ void tag_update(Depsgraph *graph);
+
+ bool is_noop() const { return (bool)evaluate == false; }
+
+ OperationDepsNode *get_entry_operation() { return this; }
+ OperationDepsNode *get_exit_operation() { return this; }
+
+ ComponentDepsNode *owner; /* component that contains the operation */
+
+ DepsEvalOperationCb evaluate; /* callback for operation */
+
+
+ uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ float eval_priority;
+ bool scheduled;
+
+ short optype; /* (eDepsOperation_Type) stage of evaluation */
+ int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+
+ int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+void DEG_register_operation_depsnodes();
+
+#endif /* __DEPSNODE_OPERATION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
new file mode 100644
index 00000000000..5eae8c087ad
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_cycle.cc
+ * \ingroup depsgraph
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <stack>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+};
+
+void deg_graph_detect_cycles(Depsgraph *graph)
+{
+ /* Not is not visited at all during traversal. */
+ const int NODE_NOT_VISITED = 0;
+ /* Node has been visited during traversal and not in current stack. */
+ const int NODE_VISITED = 1;
+ /* Node has been visited during traversal and is in current stack. */
+ const int NODE_IN_STACK = 2;
+
+ std::stack<StackEntry> traversal_stack;
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ bool has_inlinks = false;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ has_inlinks = true;
+ }
+ }
+ if (has_inlinks == false) {
+ StackEntry entry;
+ entry.node = node;
+ entry.from = NULL;
+ entry.via_relation = NULL;
+ traversal_stack.push(entry);
+ node->done = NODE_IN_STACK;
+ }
+ else {
+ node->done = NODE_NOT_VISITED;
+ }
+ }
+
+ while (!traversal_stack.empty()) {
+ StackEntry &entry = traversal_stack.top();
+ OperationDepsNode *node = entry.node;
+ bool all_child_traversed = true;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if (to->done == NODE_IN_STACK) {
+ printf("Dependency cycle detected:\n");
+ printf(" '%s' depends on '%s' through '%s'\n",
+ to->full_identifier().c_str(),
+ node->full_identifier().c_str(),
+ rel->name);
+
+ StackEntry *current = &entry;
+ while (current->node != to) {
+ BLI_assert(current != NULL);
+ printf(" '%s' depends on '%s' through '%s'\n",
+ current->node->full_identifier().c_str(),
+ current->from->node->full_identifier().c_str(),
+ current->via_relation->name);
+ current = current->from;
+ }
+ /* TODO(sergey): So called roussian rlette cycle solver. */
+ rel->flag |= DEPSREL_FLAG_CYCLIC;
+ }
+ else if (to->done == NODE_NOT_VISITED) {
+ StackEntry new_entry;
+ new_entry.node = to;
+ new_entry.from = &entry;
+ new_entry.via_relation = rel;
+ traversal_stack.push(new_entry);
+ to->done = NODE_IN_STACK;
+ all_child_traversed = false;
+ break;
+ }
+ }
+ }
+ if (all_child_traversed) {
+ node->done = NODE_VISITED;
+ traversal_stack.pop();
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/util/depsgraph_util_cycle.h
new file mode 100644
index 00000000000..fac38b61057
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.h
@@ -0,0 +1,37 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_cycle.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
+#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+struct Depsgraph;
+
+void deg_graph_detect_cycles(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/depsgraph_util_function.h
new file mode 100644
index 00000000000..a4301833408
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_function.h
@@ -0,0 +1,112 @@
+/*
+ * ***** 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.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_function.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
+#define __DEPSGRAPH_UTIL_FUNCTION_H__
+
+#if (__cplusplus > 199711L)
+
+#include <functional>
+
+using std::function;
+using namespace std::placeholders;
+#define function_bind std::bind
+
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+using boost::function;
+#define function_bind boost::bind
+
+#else
+
+#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+#include <cstdlib>
+
+template<typename T>
+class function {
+public:
+ function() {};
+ function(void *) {}
+ operator bool() const { return false; }
+ bool operator== (void *) { return false; }
+
+ template<typename T1>
+ void operator() (T1) {
+ BLI_assert(!"Should not be used");
+ }
+};
+
+class Wrap {
+public:
+ Wrap() {}
+ template <typename T>
+ Wrap(T /*arg*/) {}
+};
+
+template <typename T>
+void *function_bind(T func,
+ Wrap arg1 = Wrap(),
+ Wrap arg2 = Wrap(),
+ Wrap arg3 = Wrap(),
+ Wrap arg4 = Wrap(),
+ Wrap arg5 = Wrap(),
+ Wrap arg6 = Wrap(),
+ Wrap arg7 = Wrap())
+{
+ BLI_assert(!"Should not be used");
+ (void)func;
+ (void)arg1;
+ (void)arg2;
+ (void)arg3;
+ (void)arg4;
+ (void)arg5;
+ (void)arg6;
+ (void)arg7;
+ return NULL;
+}
+
+#define _1 Wrap()
+#define _2 Wrap()
+#define _3 Wrap()
+#define _4 Wrap()
+
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
new file mode 100644
index 00000000000..bc75627a026
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_hash.h
@@ -0,0 +1,72 @@
+/*
+ * ***** 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.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_hash.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_HASH_H__
+#define __DEPSGRAPH_UTIL_HASH_H__
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# define DEG_HASH_NAMESPACE_BEGIN
+# define DEG_HASH_NAMESPACE_END
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std {
+# define DEG_HASH_NAMESPACE_END }
+using std::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+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 /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
new file mode 100644
index 00000000000..0eae1d79e34
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_map.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_map.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_MAP_H__
+#define __DEPSGRAPH_UTIL_MAP_H__
+
+#include <map>
+
+#include "depsgraph_util_hash.h"
+
+using std::map;
+using std::pair;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <map>
+typedef std::map unordered_map;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+using std::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
new file mode 100644
index 00000000000..80b37ec622d
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
@@ -0,0 +1,136 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc
+ * \ingroup depsgraph
+ */
+
+#include "depsgraph_util_pchanmap.h"
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+}
+
+static void free_rootpchanmap_valueset(void *val)
+{
+ /* Just need to free the set itself - the names stored are all references. */
+ GSet *values = (GSet *)val;
+ BLI_gset_free(values, NULL);
+}
+
+RootPChanMap::RootPChanMap()
+{
+ /* Just create empty map. */
+ m_map = BLI_ghash_str_new("RootPChanMap");
+}
+
+RootPChanMap::~RootPChanMap()
+{
+ /* Free the map, and all the value sets. */
+ BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+}
+
+/* Debug contents of map */
+void RootPChanMap::print_debug()
+{
+ GHashIterator it1;
+ GSetIterator it2;
+
+ printf("Root PChan Map:\n");
+ GHASH_ITER(it1, m_map) {
+ const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
+ GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
+
+ printf(" %s : { ", item);
+ GSET_ITER(it2, values) {
+ const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
+ printf("%s, ", val);
+ }
+ printf("}\n");
+ }
+}
+
+/* Add a mapping. */
+void RootPChanMap::add_bone(const char *bone, const char *root)
+{
+ if (BLI_ghash_haskey(m_map, bone)) {
+ /* Add new entry, but only add the root if it doesn't already
+ * exist in there.
+ */
+ GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ BLI_gset_add(values, (void *)root);
+ }
+ else {
+ /* Create new set and mapping. */
+ GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
+ BLI_ghashutil_strcmp,
+ "RootPChanMap Value Set");
+ BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+
+ /* Add new entry now. */
+ BLI_gset_insert(values, (void *)root);
+ }
+}
+
+/* Check if there's a common root bone between two bones. */
+bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
+{
+ /* Ensure that both are in the map... */
+ if (BLI_ghash_haskey(m_map, bone1) == false) {
+ //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ if (BLI_ghash_haskey(m_map, bone2) == false) {
+ //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+
+ GSetIterator it1, it2;
+ GSET_ITER(it1, bone1_roots) {
+ GSET_ITER(it2, bone2_roots) {
+ const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
+ const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
+
+ if (strcmp(v1, v2) == 0) {
+ //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
+ return true;
+ }
+ }
+ }
+
+ //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
+ return false;
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
new file mode 100644
index 00000000000..b7f4c495933
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__
+#define __DEPSGRAPH_UTIL_PCHANMAP_H__
+
+struct RootPChanMap {
+ /* ctor and dtor - Create and free the internal map respectively. */
+ RootPChanMap();
+ ~RootPChanMap();
+
+ /* Debug contents of map. */
+ void print_debug();
+
+ /* Add a mapping. */
+ void add_bone(const char *bone, const char *root);
+
+ /* Check if there's a common root bone between two bones. */
+ bool has_common_root(const char *bone1, const char *bone2);
+
+private:
+ /* The actual map:
+ * - Keys are "strings" (const char *) - not dynamically allocated.
+ * - Values are "sets" (const char *) - not dynamically allocated.
+ *
+ * We don't use the C++ maps here, as it's more convenient to use
+ * Blender's GHash and be able to compare by-value instead of by-ref.
+ */
+ struct GHash *m_map;
+};
+
+#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/depsgraph_util_set.h
new file mode 100644
index 00000000000..008ec6b74ca
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_set.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.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_set.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_SET_H__
+#define __DEPSGRAPH_UTIL_SET_H__
+
+#include <set>
+
+#include "depsgraph_util_hash.h"
+
+using std::set;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <set>
+typedef std::set unordered_set;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_set>
+using std::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_SET_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
new file mode 100644
index 00000000000..98192a9540f
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
@@ -0,0 +1,139 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne,
+ * Sergey Sharybin,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_transitive.cc
+ * \ingroup depsgraph
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_transitive.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* -------------------------------------------------- */
+
+/* Performs a transitive reduction to remove redundant relations.
+ * http://en.wikipedia.org/wiki/Transitive_reduction
+ *
+ * XXX The current implementation is somewhat naive and has O(V*E) worst case
+ * runtime.
+ * A more optimized algorithm can be implemented later, e.g.
+ *
+ * http://www.sciencedirect.com/science/article/pii/0304397588900321/pdf?md5=3391e309b708b6f9cdedcd08f84f4afc&pid=1-s2.0-0304397588900321-main.pdf
+ *
+ * Care has to be taken to make sure the algorithm can handle the cyclic case
+ * too! (unless we can to prevent this case early on).
+ */
+
+enum {
+ OP_VISITED = 1,
+ OP_REACHABLE = 2,
+};
+
+static void deg_graph_tag_paths_recursive(DepsNode *node)
+{
+ if (node->done & OP_VISITED)
+ return;
+ node->done |= OP_VISITED;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
+ it != node->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ /* Do this only in inlinks loop, so the target node does not get
+ * flagged.
+ */
+ rel->from->done |= OP_REACHABLE;
+ }
+}
+
+void deg_graph_transitive_reduction(Depsgraph *graph)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
+ it_target != graph->operations.end();
+ ++it_target)
+ {
+ OperationDepsNode *target = *it_target;
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* mark nodes from which we can reach the target
+ * start with children, so the target node and direct children are not
+ * flagged.
+ */
+ target->done |= OP_VISITED;
+ for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
+ it != target->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ }
+
+ /* Eemove redundant paths to the target. */
+ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
+ it_rel != target->inlinks.end();
+ )
+ {
+ DepsRelation *rel = *it_rel;
+ /* Increment in advance, so we can safely remove the relation. */
+ ++it_rel;
+
+ if (rel->from->type == DEPSNODE_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.
+ */
+ }
+ else if (rel->from->done & OP_REACHABLE) {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/util/depsgraph_util_transitive.h
new file mode 100644
index 00000000000..a80a1d783d7
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.h
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne
+ * Sergey Sharybin,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_transitive.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+
+struct Depsgraph;
+
+void deg_graph_transitive_reduction(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 37c40052275..ebd05d8b16b 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -110,7 +110,7 @@ static void acf_generic_root_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUS
/* backdrop for top-level widgets (Scene and Object only) */
static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -136,7 +136,7 @@ static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem
/* backdrop for data expanders under top-level Scene/Object */
static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -177,7 +177,7 @@ static bool acf_show_channel_colors(bAnimContext *ac)
/* get backdrop color for generic channels */
static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3])
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
bActionGroup *grp = NULL;
short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0;
bool showGroupColors = acf_show_channel_colors(ac);
@@ -217,7 +217,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
/* backdrop for generic channels */
static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -269,7 +269,7 @@ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListE
/* basic offset for channels derived from indention */
static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
if (acf && acf->get_indent_level)
return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE;
@@ -409,7 +409,7 @@ static void acf_summary_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(al
/* backdrop for summary widget */
static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float color[3];
@@ -790,7 +790,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
/* backdrop for group widget */
static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -1017,6 +1017,149 @@ static bAnimChannelType ACF_FCURVE =
acf_fcurve_setting_ptr /* pointer for setting */
};
+/* NLA Control FCurves Expander ----------------------- */
+
+/* get backdrop color for nla controls widget */
+static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3])
+{
+ // TODO: give this its own theme setting?
+ UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color);
+}
+
+/* backdrop for nla controls expander widget */
+static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ View2D *v2d = &ac->ar->v2d;
+ short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
+ short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
+ float color[3];
+
+ /* set backdrop drawing color */
+ acf->get_backdrop_color(ac, ale, color);
+ glColor3fv(color);
+
+ /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
+ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+}
+
+/* name for nla controls expander entries */
+static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name)
+{
+ BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
+}
+
+/* check if some setting exists for this channel */
+static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
+{
+ /* for now, all settings are supported, though some are only conditionally */
+ switch (setting) {
+ /* supported */
+ case ACHANNEL_SETTING_EXPAND:
+ return true;
+
+ // TOOD: selected?
+
+ default: /* unsupported */
+ return false;
+ }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ *neg = true;
+ return ADT_NLA_SKEYS_COLLAPSED;
+
+ default:
+ /* this shouldn't happen */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type)
+{
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* all flags are just in adt->flag for now... */
+ return GET_ACF_FLAG_PTR(adt->flag, type);
+}
+
+static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_NLA;
+}
+
+/* NLA Control FCurves Expander type define */
+static bAnimChannelType ACF_NLACONTROLS =
+{
+ "NLA Controls Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_nla_controls_color, /* backdrop color */
+ acf_nla_controls_backdrop, /* backdrop */
+ acf_generic_indention_0, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_controls_name, /* name */
+ NULL, /* name prop */
+ acf_nla_controls_icon, /* icon */
+
+ acf_nla_controls_setting_valid, /* has setting */
+ acf_nla_controls_setting_flag, /* flag for setting */
+ acf_nla_controls_setting_ptr /* pointer for setting */
+};
+
+
+/* NLA Control F-Curve -------------------------------- */
+
+/* name for nla control fcurve entries */
+static void acf_nla_curve_name(bAnimListElem *ale, char *name)
+{
+ NlaStrip *strip = ale->owner;
+ FCurve *fcu = ale->data;
+ PropertyRNA *prop;
+
+ /* try to get RNA property that this shortened path (relative to the strip) refers to */
+ prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path);
+ if (prop) {
+ /* "name" of this strip displays the UI identifier + the name of the NlaStrip */
+ BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name);
+ }
+ else {
+ /* unknown property... */
+ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index);
+ }
+}
+
+
+/* NLA Control F-Curve type define */
+static bAnimChannelType ACF_NLACURVE =
+{
+ "NLA Control F-Curve", /* type name */
+ ACHANNEL_ROLE_CHANNEL, /* role */
+
+ acf_generic_channel_color, /* backdrop color */
+ acf_generic_channel_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_curve_name, /* name */
+ acf_fcurve_name_prop, /* name prop */
+ NULL, /* icon */
+
+ acf_fcurve_setting_valid, /* has setting */
+ acf_fcurve_setting_flag, /* flag for setting */
+ acf_fcurve_setting_ptr /* pointer for setting */
+};
+
/* Object Action Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -3063,7 +3206,7 @@ static void acf_nlaaction_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, fl
/* backdrop for nla action channel */
static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
AnimData *adt = ale->adt;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -3222,6 +3365,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */
animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */
+ animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */
+ animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */
+
animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
@@ -3256,7 +3402,7 @@ static void ANIM_init_channel_typeinfo_data(void)
}
/* Get type info from given channel type */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* santiy checks */
if (ale == NULL)
@@ -3277,7 +3423,7 @@ bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* print indents */
for (; indent_level > 0; indent_level--)
@@ -3309,7 +3455,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
*/
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3382,7 +3528,7 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
*/
void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3430,10 +3576,26 @@ void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel
// width of rename textboxes
#define RENAME_TEXT_WIDTH (5 * U.widget_unit)
+
+/* Helper - Check if a channel needs renaming */
+static bool achannel_is_being_renamed(const bAnimContext *ac, const bAnimChannelType *acf, size_t channel_index)
+{
+ if (acf->name_prop && ac->ads) {
+ /* if rename index matches, this channel is being renamed */
+ if (ac->ads->renameIndex == channel_index + 1) {
+ return true;
+ }
+ }
+
+ /* not being renamed */
+ return false;
+}
+
+
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short selected, offset;
float y, ymid, ytext;
@@ -3491,7 +3653,7 @@ 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)) {
/* for F-Curves, draw color-preview of curve behind checkbox */
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
@@ -3518,8 +3680,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
}
/* step 5) draw name ............................................... */
- /* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */
- if (acf->name) {
+ /* Don't draw this if renaming... */
+ if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
@@ -3537,7 +3699,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
/* draw red underline if channel is disabled */
- if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
/* FIXME: replace hardcoded color here, and check on extents! */
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
@@ -3604,7 +3766,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* (only only F-Curves really can support them for now)
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
offset += SLIDER_WIDTH;
}
@@ -3771,8 +3933,46 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
MEM_freeN(rna_path);
}
+/* callback for NLA Control Curve widget sliders - insert keyframes */
+static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_poin), void *fcu_poin)
+{
+ /* ID *id = (ID *)id_poin; */
+ FCurve *fcu = (FCurve *)fcu_poin;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ ReportList *reports = CTX_wm_reports(C);
+ Scene *scene = CTX_data_scene(C);
+ short flag = 0;
+ bool done = false;
+ float cfra;
+
+ /* get current frame - *no* NLA mapping should be done */
+ cfra = (float)CFRA;
+
+ /* get flags for keyframing */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* get pointer and property from the slider - this should all match up with the NlaStrip required... */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (fcu && prop) {
+ /* set the special 'replace' flag if on a keyframe */
+ if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+ flag |= INSERTKEY_REPLACE;
+
+ /* insert a keyframe for this F-Curve */
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+
+ if (done)
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
/* Draw a widget for some setting */
-static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf,
+static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAnimChannelType *acf,
uiBlock *block, int xpos, int ypos, int setting)
{
short ptrsize, butType;
@@ -3793,7 +3993,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF);
icon = ICON_VISIBLE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
else
tooltip = TIP_("Channels are visible in Graph Editor for editing");
@@ -3828,7 +4028,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
icon = ICON_MUTE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
}
else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) {
@@ -3912,7 +4112,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float y, ymid /*, ytext*/;
short offset;
@@ -3991,36 +4191,32 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
}
/* step 4) draw text - check if renaming widget is in use... */
- if (acf->name_prop && ac->ads) {
- float channel_height = ymaxc - yminc;
+ if (achannel_is_being_renamed(ac, acf, channel_index)) {
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
- /* if rename index matches, add widget for this */
- if (ac->ads->renameIndex == channel_index + 1) {
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
+ /* draw renaming widget if we can get RNA pointer for it
+ * NOTE: property may only be available in some cases, even if we have
+ * a callback available (e.g. broken F-Curve rename)
+ */
+ if (acf->name_prop(ale, &ptr, &prop)) {
+ const float channel_height = ymaxc - yminc;
+ uiBut *but;
- /* draw renaming widget if we can get RNA pointer for it
- * NOTE: property may only be available in some cases, even if we have
- * a callback available (e.g. broken F-Curve rename)
- */
- if (acf->name_prop(ale, &ptr, &prop)) {
- uiBut *but;
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
- but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
- &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
-
- /* copy what outliner does here, see outliner_buttons */
- if (UI_but_active_only(C, ac->ar, block, but) == false) {
- ac->ads->renameIndex = 0;
-
- /* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
- }
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
+ &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
+
+ /* copy what outliner does here, see outliner_buttons */
+ if (UI_but_active_only(C, ac->ar, block, but) == false) {
+ ac->ads->renameIndex = 0;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* send notifiers */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
}
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -4097,7 +4293,7 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* and wouldn't be able to auto-keyframe...
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
// TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough
offset += SLIDER_WIDTH;
@@ -4105,7 +4301,28 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
/* need backdrop behind sliders... */
UI_block_emboss_set(block, UI_EMBOSS);
- if (ale->id) { /* Slider using RNA Access -------------------- */
+ if (ale->owner) { /* Slider using custom RNA Access ---------- */
+ if (ale->type == ANIMTYPE_NLACURVE) {
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers */
+ RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr);
+ prop = RNA_struct_find_property(&ptr, fcu->rna_path);
+
+ /* create property slider */
+ if (prop) {
+ uiBut *but;
+
+ /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+ but = uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc);
+ UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data);
+ }
+ }
+ }
+ else if (ale->id) { /* Slider using RNA Access --------------- */
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
char *rna_path = NULL;
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index d8ad6506186..f9e3c8a9fa6 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "BKE_depsgraph.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -101,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -157,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel_data;
fcu->flag |= FCURVE_ACTIVE;
@@ -255,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
if (ale->flag & FCURVE_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
@@ -339,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -444,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
return;
}
else {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
if (acf == NULL) {
printf("ERROR: no channel info for the changed channel\n");
@@ -473,7 +478,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go backwards in the list, until the highest-ranking element (by indention has been covered) */
for (ale = match->prev; ale; ale = ale->prev) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -517,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
for (ale = match->next; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -847,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel;
@@ -868,7 +874,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
default:
- printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+ printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
return;
}
@@ -1191,6 +1197,40 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
/* ------------------- */
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+ ListBase anim_data_visible = {NULL, NULL};
+
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* get rearranging function */
+ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+
+ if (rearrange_func == NULL)
+ return;
+
+ /* skip if these curves aren't being shown */
+ if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+ return;
+
+ /* Filter visible data. */
+ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+
+ /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+ &anim_data_visible);
+ }
+ }
+
+ /* free temp data */
+ BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
{
ListBase anim_data = {NULL, NULL};
@@ -1278,13 +1318,29 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
rearrange_driver_channels(&ac, adt, mode);
break;
+ case ANIMCONT_ACTION: /* Single Action only... */
case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
- default: /* some collection of actions */
+ {
if (adt->action)
rearrange_action_channels(&ac, adt->action, mode);
else if (G.debug & G_DEBUG)
printf("Animdata has no action\n");
break;
+ }
+
+ default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+ {
+ /* NLA Control Curves */
+ if (adt->nla_tracks.first)
+ rearrange_nla_control_channels(&ac, adt, mode);
+
+ /* Action */
+ if (adt->action)
+ rearrange_action_channels(&ac, adt->action, mode);
+ else if (G.debug & G_DEBUG)
+ printf("Animdata has no action\n");
+ break;
+ }
}
}
@@ -1602,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
break;
}
+ case ANIMTYPE_NLACURVE:
+ {
+ /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+
+ if (STREQ(fcu->rna_path, "strip_time")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+ }
+ else if (STREQ(fcu->rna_path, "influence")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+ }
+ else {
+ printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+ }
+
+ /* unlink and free the F-Curve */
+ BLI_remlink(&strip->fcurves, fcu);
+ free_fcurve(fcu);
+ break;
+ }
case ANIMTYPE_GPLAYER:
{
/* Grease Pencil layer */
@@ -1631,7 +1708,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+ DAG_relations_tag_update(CTX_data_main(C));
+
return OPERATOR_FINISHED;
}
@@ -2041,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_free_animdata(id);
+ BKE_animdata_free(id);
}
}
@@ -2420,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
/* ******************* Rename Operator ***************************** */
/* Allow renaming some channels by clicking on them */
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
{
ListBase anim_data = {NULL, NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
bAnimListElem *ale;
int filter;
+ bool success = false;
/* get the channel that was clicked on */
/* filter channels */
@@ -2440,7 +2519,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
ANIM_animdata_freelist(&anim_data);
- return;
+ return false;
}
/* check that channel can be renamed */
@@ -2460,6 +2539,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
*/
if (ac->ads) {
ac->ads->renameIndex = channel_index + 1;
+ success = true;
}
}
}
@@ -2467,22 +2547,18 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
/* free temp data and tag for refresh */
ANIM_animdata_freelist(&anim_data);
ED_region_tag_redraw(ac->ar);
+ return success;
}
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
{
- bAnimContext ac;
ARegion *ar;
View2D *v2d;
int channel_index;
float x, y;
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
/* get useful pointers from animation context data */
- ar = ac.ar;
+ ar = ac->ar;
v2d = &ar->v2d;
/* figure out which channel user clicked in
@@ -2490,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
* so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
* ACHANNEL_HEIGHT_HALF.
*/
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- if (ac.datatype == ANIMCONT_NLA) {
- SpaceNla *snla = (SpaceNla *)ac.sl;
+ if (ac->datatype == ANIMCONT_NLA) {
+ SpaceNla *snla = (SpaceNla *)ac->sl;
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
}
-
+
+ return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
/* handle click */
- rename_anim_channels(&ac, channel_index);
-
- return OPERATOR_FINISHED;
+ if (rename_anim_channels(&ac, channel_index))
+ return OPERATOR_FINISHED;
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
}
static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2727,7 +2819,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
- case ANIMTYPE_FCURVE:
+ case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -2744,7 +2837,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
if (fcu->flag & FCURVE_SELECTED)
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
@@ -2767,6 +2860,19 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* toggle expand
+ * - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+ * let's just use it for easier expand/collapse for now
+ */
+ adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ break;
+ }
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = (bGPdata *)ale->data;
@@ -2918,6 +3024,105 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool success = false;
+ FCurve *fcu;
+ int i;
+
+ /* get the channel that was clicked on */
+ /* filter channels */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get channel from index */
+ ale = BLI_findlink(&anim_data, channel_index);
+ if (ale == NULL) {
+ /* channel not found */
+ if (G.debug & G_DEBUG)
+ printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+
+ fcu = (FCurve *)ale->key_data;
+ success = (fcu != NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ /* F-Curve may not have any keyframes */
+ if (fcu && fcu->bezt) {
+ BezTriple *bezt;
+
+ if (!extend) {
+ filter = (ANIMFILTER_DATA_VISIBLE);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+ if (fcu_inner) {
+ for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = 0;
+ }
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+ }
+ }
+
+ /* free temp data and tag for refresh */
+ ED_region_tag_redraw(ac->ar);
+ return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
+ /* handle click */
+ if (select_anim_channel_keys(&ac, channel_index, extend)) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Channel keyframes";
+ ot->idname = "ANIM_OT_channel_select_keys";
+ ot->description = "Select all keyframes of channel under mouse";
+
+ /* api callbacks */
+ ot->invoke = animchannels_channel_select_keys_invoke;
+ ot->poll = animedit_poll_channels_active;
+
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************************************************************************** */
/* Operator Registration */
@@ -2927,8 +3132,9 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_select_border);
WM_operatortype_append(ANIM_OT_channels_click);
+ WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
-
+
WM_operatortype_append(ANIM_OT_channels_find);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
@@ -2968,7 +3174,9 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
/* rename */
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
+ WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index eb57907c9ec..a38f5dbc8ea 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -73,8 +73,10 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
/* tag AnimData for refresh so that other views will update in realtime with these changes */
adt = BKE_animdata_from_id(id);
- if (adt)
+ if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(id, OB_RECALC_TIME);
+ }
/* update data */
fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 0e052279796..d5945425576 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -34,16 +34,25 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_dlrbTree.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
+#include "BKE_mask.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_draw.h"
#include "RNA_access.h"
@@ -173,10 +182,14 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
if (G.is_rendering) return NULL;
/* handling depends on the type of animation-context we've got */
- if (ale)
- return ale->adt;
- else
- return NULL;
+ if (ale) {
+ /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
+ if (ale->type != ANIMTYPE_NLACURVE)
+ return ale->adt;
+ }
+
+ /* cannot handle... */
+ return NULL;
}
/* ------------------- */
@@ -262,19 +275,26 @@ short ANIM_get_normalization_flags(bAnimContext *ac)
return 0;
}
-static float normalzation_factor_get(FCurve *fcu, short flag)
+static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
{
- float factor = 1.0f;
+ float factor = 1.0f, offset = 0.0f;
if (flag & ANIM_UNITCONV_RESTORE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+
return 1.0f / fcu->prev_norm_factor;
}
if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
if (G.moving & G_TRANSFORM_FCURVES) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
@@ -283,32 +303,65 @@ static float normalzation_factor_get(FCurve *fcu, short flag)
BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
+ float min_coord = FLT_MAX;
+ float range;
if (fcu->totvert < 1) {
return 1.0f;
}
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, fabsf(bezt->vec[0][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[1][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[2][1]));
+ 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]);
+ }
+ }
+ }
+ else {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ 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]);
+ }
}
- if (max_coord > FLT_EPSILON) {
- factor = 1.0f / max_coord;
+ range = max_coord - min_coord;
+
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
}
+ offset = -min_coord - range / 2.0f;
}
+
+ if (r_offset) {
+ *r_offset = offset;
+ }
+
fcu->prev_norm_factor = factor;
+ fcu->prev_offset = offset;
return factor;
}
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag)
+float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
- return normalzation_factor_get(fcu, flag);
+ return normalization_factor_get(scene, fcu, flag, r_offset);
}
+ if (r_offset)
+ *r_offset = 0.0f;
+
/* sanity checks */
if (id && fcu && fcu->rna_path) {
PointerRNA ptr, id_ptr;
@@ -336,4 +389,137 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag
return 1.0f;
}
+static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ bDopeSheet ads = {NULL};
+ DLRBT_Tree keys;
+ ActKeyColumn *aknext, *akprev;
+ float cfranext, cfraprev;
+ bool donenext = false, doneprev = false;
+ int nextcount = 0, prevcount = 0;
+
+ cfranext = cfraprev = (float)(CFRA);
+
+ /* init binarytree-list for getting keyframes */
+ BLI_dlrbTree_init(&keys);
+
+ /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
+ /* only selected channels are included */
+ ads.filterflag |= ADS_FILTER_ONLYSEL;
+ }
+
+ /* populate tree with keyframe nodes */
+ scene_to_keylist(&ads, scene, &keys, NULL);
+
+ if (ob)
+ ob_to_keylist(&ads, ob, &keys, NULL);
+
+ gpencil_to_keylist(&ads, gpd, &keys);
+
+ if (mask) {
+ MaskLayer *masklay = BKE_mask_layer_active(mask);
+ mask_to_keylist(&ads, masklay, &keys);
+ }
+
+ /* build linked-list for searching */
+ BLI_dlrbTree_linkedlist_sync(&keys);
+
+ /* find matching keyframe in the right direction */
+ do {
+ aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
+
+ if (aknext) {
+ if (CFRA == (int)aknext->cfra) {
+ /* make this the new starting point for the search and ignore */
+ cfranext = aknext->cfra;
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++nextcount == U.view_frame_keyframes)
+ donenext = true;
+ }
+ cfranext = aknext->cfra;
+ }
+ } while ((aknext != NULL) && (donenext == false));
+
+ do {
+ akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
+
+ if (akprev) {
+ if (CFRA == (int)akprev->cfra) {
+ /* make this the new starting point for the search */
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++prevcount == U.view_frame_keyframes)
+ doneprev = true;
+ }
+ cfraprev = akprev->cfra;
+ }
+ } while ((akprev != NULL) && (doneprev == false));
+
+ /* free temp stuff */
+ BLI_dlrbTree_free(&keys);
+
+ /* any success? */
+ if (doneprev || donenext) {
+ if (doneprev)
+ *prevfra = cfraprev;
+ else
+ *prevfra = CFRA - (cfranext - CFRA);
+
+ if (donenext)
+ *nextfra = cfranext;
+ else
+ *nextfra = CFRA + (CFRA - cfraprev);
+
+ return true;
+ }
+
+ return false;
+}
+
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ rctf newrct;
+ int nextfra, prevfra;
+
+ switch (U.view_frame_type) {
+ case ZOOM_FRAME_MODE_SECONDS:
+ newrct.xmax = scene->r.cfra + U.view_frame_seconds * FPS + 1;
+ newrct.xmin = scene->r.cfra - U.view_frame_seconds * FPS - 1;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+
+ /* hardest case of all, look for all keyframes around frame and display those */
+ case ZOOM_FRAME_MODE_KEYFRAMES:
+ if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
+ newrct.xmax = nextfra;
+ newrct.xmin = prevfra;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+ /* else drop through, keep range instead */
+
+ case ZOOM_FRAME_MODE_KEEP_RANGE:
+ default:
+ newrct.xmax = scene->r.cfra + (w / 2);
+ newrct.xmin = scene->r.cfra - (w / 2);
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+
+ UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
+}
/* *************************************************** */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index d6daa64a9f2..75f5eb17b09 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -423,6 +423,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
* - nlaOk: line or block of code to execute for NLA tracks+strips case
* - driversOk: line or block of code to execute for Drivers case
+ * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
* - keysOk: line or block of code for Keyframes case
*
* The checks for the various cases are as follows:
@@ -433,9 +434,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* converted to a new NLA strip, and the filtering options allow this
* 2C) allow non-animated datablocks to be included so that datablocks can be added
* 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
- * 4) normal keyframes: only when there is an active action
+ * 4A) nla strip keyframes: these are the per-strip controls for time and influence
+ * 4B) normal keyframes: only when there is an active action
*/
-#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
+#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
{ \
if ((id)->adt) { \
if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
@@ -456,6 +458,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
} \
} \
else { \
+ if (ANIMDATA_HAS_NLA(id)) { \
+ nlaKeysOk \
+ } \
if (ANIMDATA_HAS_KEYS(id)) { \
keysOk \
} \
@@ -786,6 +791,16 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)data;
+
+ ale->flag = adt->flag;
+
+ ale->key_data = NULL;
+ ale->datatype = ALE_NONE;
+ break;
+ }
case ANIMTYPE_GROUP:
{
bActionGroup *agrp = (bActionGroup *)data;
@@ -977,7 +992,7 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
{
bAnimListElem ale_dummy = {NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
/* create a dummy wrapper for the F-Curve */
ale_dummy.type = ANIMTYPE_FCURVE;
@@ -1286,7 +1301,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
* - active track should still get shown though (even though it has disabled flag set)
*/
// FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && (adt->act_track != nlt))
continue;
/* only work with this channel and its subchannels if it is editable */
@@ -1295,6 +1310,30 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
+ /* name based filtering... */
+ if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ bool track_ok = false, strip_ok = false;
+
+ /* check if the name of the track, or the strips it has are ok... */
+ track_ok = BLI_strcasestr(nlt->name, ads->searchstr);
+
+ if (track_ok == false) {
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (BLI_strcasestr(strip->name, ads->searchstr)) {
+ strip_ok = true;
+ break;
+ }
+ }
+ }
+
+ /* skip if both fail this test... */
+ if (!track_ok && !strip_ok) {
+ continue;
+ }
+ }
+
+ /* add the track now that it has passed all our tests */
ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
}
}
@@ -1305,6 +1344,80 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
return items;
}
+/* Include the control FCurves per NLA Strip in the channel list
+ * NOTE: This is includes the expander too...
+ */
+static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add control curves from each NLA strip... */
+ /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
+ BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0))
+ {
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ ListBase strip_curves = {NULL, NULL};
+ size_t strip_items = 0;
+
+ /* create the raw items */
+ strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
+
+ /* change their types and add extra data
+ * - There is no point making a separate copy of animfilter_fcurves for this now/yet,
+ * unless we later get per-element control curves for other stuff too
+ */
+ if (strip_items) {
+ bAnimListElem *ale, *ale_n = NULL;
+
+ for (ale = strip_curves.first; ale; ale = ale_n) {
+ ale_n = ale->next;
+
+ /* change the type to being a FCurve for editing NLA strip controls */
+ BLI_assert(ale->type == ANIMTYPE_FCURVE);
+
+ ale->type = ANIMTYPE_NLACURVE;
+ ale->owner = strip;
+
+ ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */
+ }
+ }
+
+ /* add strip curves to the set of channels inside the group being collected */
+ BLI_movelisttolist(&tmp_data, &strip_curves);
+ BLI_assert(BLI_listbase_is_empty(&strip_curves));
+ tmp_items += strip_items;
+ }
+ }
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* add the expander as a channel first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* currently these channels cannot be selected, so they should be skipped */
+ if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
+ ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the numebr of items added to the list */
+ return items;
+}
+
/* determine what animation data from AnimData block should get displayed */
static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
{
@@ -1332,6 +1445,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
{ /* Drivers */
items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
},
+ { /* NLA Control Keyframes */
+ items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
+ },
{ /* Keyframes */
items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
}
@@ -2214,6 +2330,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2385,6 +2502,7 @@ static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, bD
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2804,7 +2922,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
/* unhandled */
default:
{
- printf("ANIM_animdata_filter() - Invalid datatype argument %d\n", datatype);
+ printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype);
break;
}
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 140b7e0b117..40376c38c3b 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -266,8 +266,20 @@ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
- if (markers == NULL)
+ if (lb) {
+ /* Clear the list first, since callers have no way of knowing
+ * whether this terminated early otherwise. This may lead
+ * to crashes if the user didn't clear the memory first.
+ */
+ lb->first = lb->last = NULL;
+ }
+ else {
+ return;
+ }
+
+ if (markers == NULL) {
return;
+ }
for (marker = markers->first; marker; marker = marker->next)
add_marker_to_cfra_elem(lb, marker, only_sel);
@@ -487,11 +499,32 @@ static int ed_markers_poll_selected_markers(bContext *C)
return ED_markers_get_first_selected(markers) != NULL;
}
+static int ed_markers_poll_selected_no_locked_markers(bContext *C)
+{
+ ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ if (ts->lock_markers)
+ return 0;
+
+ /* first things first: markers can only exist in timeline views */
+ if (ED_operator_animview_active(C) == 0)
+ return 0;
+
+ /* check if some marker is selected */
+ return ED_markers_get_first_selected(markers) != NULL;
+}
+
+
/* special poll() which checks if there are any markers at all first */
static int ed_markers_poll_markers_exist(bContext *C)
{
ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts->lock_markers)
+ return 0;
+
/* first things first: markers can only exist in timeline views */
if (ED_operator_animview_active(C) == 0)
return 0;
@@ -929,11 +962,11 @@ static void MARKER_OT_move(wmOperatorType *ot)
ot->exec = ed_marker_move_exec;
ot->invoke = ed_marker_move_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna storage */
RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
@@ -1022,7 +1055,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
ot->exec = ed_marker_duplicate_exec;
ot->invoke = ed_marker_duplicate_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
@@ -1352,7 +1385,7 @@ static void MARKER_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_delete_invoke_wrapper;
ot->exec = ed_marker_delete_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1400,7 +1433,7 @@ static void MARKER_OT_rename(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_rename_invoke_wrapper;
ot->exec = ed_marker_rename_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1428,6 +1461,11 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (scene_to->toolsettings->lock_markers) {
+ BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers");
+ return OPERATOR_CANCELLED;
+ }
+
/* copy markers */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
@@ -1503,13 +1541,13 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bind Camera to Markers";
- ot->description = "Bind the active camera to selected markers(s)";
+ ot->description = "Bind the active camera to selected marker(s)";
ot->idname = "MARKER_OT_camera_bind";
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index cbcbc8743f1..2de42933dc0 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -107,7 +107,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -247,7 +247,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR;
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 67ba82f1858..b2a34d7c317 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -42,6 +42,7 @@
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -84,7 +85,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
return NULL;
@@ -450,7 +451,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -504,7 +505,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index bcdad1c93ad..2c0018b000d 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -78,7 +78,7 @@
static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
{
FModifier *fcm = (FModifier *)fcm_v;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
@@ -555,7 +555,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho
void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
uiLayout *box, *row, *sub, *col;
uiBlock *block;
uiBut *but;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index d2dbe961b42..9e38dd5507d 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -528,7 +528,7 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
}
/* NOTE: we don't use the straight alpha from the theme, or else effects such as
- * greying out protected/muted channels doesn't work correctly!
+ * graying out protected/muted channels doesn't work correctly!
*/
inner_col[3] *= alpha;
glColor4fv(inner_col);
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 2d869d272bd..b3dc0021f00 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -199,13 +199,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+ if (!(bezt->f2 & SELECT)) {
+ lastb = fcu->bezt;
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
/* Loop through BezTriples, comparing them. Skip any that do
* not fit the criteria for "ok" points.
*/
for (i = 1; i < totCount; i++) {
float prev[2], cur[2], next[2];
-
+
/* get BezTriples and their values */
if (i < (totCount - 1)) {
beztn = (old_bezts + (i + 1));
@@ -217,10 +221,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
}
lastb = (fcu->bezt + (fcu->totvert - 1));
bezt = (old_bezts + i);
-
+
/* get references for quicker access */
prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
+
+ if (!(bezt->f2 & SELECT)) {
+ insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ continue;
+ }
/* check if current bezt occurs at same time as last ok */
if (IS_EQT(cur[0], prev[0], thresh)) {
@@ -228,7 +239,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
* if there is a considerable distance between the points, and also if the
* current is further away than the next one is to the previous.
*/
- if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
(IS_EQT(next[1], prev[1], thresh) == 0))
{
/* only add if current is further away from previous */
@@ -548,24 +559,15 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
* storing the relevant information here helps avoiding crashes if we undo-repaste */
if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
Object *ob = (Object *)aci->id;
- char *str_start;
-
- if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
- bPoseChannel *pchan;
- int length = 0;
- char *str_end;
-
- str_start += 12;
- str_end = strchr(str_start, '\"');
- length = str_end - str_start;
- str_start[length] = 0;
- pchan = BKE_pose_channel_find_name(ob->pose, str_start);
- str_start[length] = '\"';
-
- if (pchan) {
- aci->is_bone = true;
- }
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan) {
+ aci->is_bone = true;
}
+ if (bone_name) MEM_freeN(bone_name);
}
BLI_addtail(&animcopybuf, aci);
@@ -624,22 +626,22 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
char bname_new[MAX_VGROUP_NAME];
char *str_iter, *str_end;
int length, prefix_l, postfix_l;
-
+
str_start += 12;
prefix_l = str_start - aci->rna_path;
-
+
str_end = strchr(str_start, '\"');
-
+
length = str_end - str_start;
postfix_l = strlen(str_end);
-
+
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
BKE_deform_flip_side_name(bname_new, str_start, false);
str_start[length] = '\"';
-
+
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
-
+
BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
str_iter += prefix_l;
BLI_strncpy(str_iter, bname_new, length + 1);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 7e2ce4cd3f1..85ea5526908 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -130,7 +130,7 @@ bAction *verify_adt_action(ID *id, short add)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>");
@@ -152,6 +152,10 @@ bAction *verify_adt_action(ID *id, short add)
* to the wrong places
*/
adt->action->idroot = GS(id->name);
+
+ /* tag depsgraph to be rebuilt to include time dependency */
+ /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
+ DAG_relations_tag_update(G.main);
}
/* return the action */
@@ -1696,7 +1700,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
short flag = 0;
@@ -1707,33 +1711,35 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
- }
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, flag);
-
- MEM_freeN(path);
- }
- else if (ptr.type == &RNA_NlaStrip) {
- /* handle special vars for NLA-strips */
+ if (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.
+ */
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
- success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
- BKE_report(op->reports, RPT_WARNING,
- "Failed to resolve path to property, try manually specifying this using a Keying Set instead");
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, flag);
+
+ MEM_freeN(path);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING,
+ "Failed to resolve path to property, "
+ "try manually specifying this using a Keying Set instead");
+ }
}
}
else {
@@ -1788,32 +1794,62 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
+ if (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.
+ */
+ ID *id = ptr.id.data;
+ 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;
- if (length) index = 0;
- else length = 1;
+ /* 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;
+ }
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, 0);
+ }
+ else {
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
- MEM_freeN(path);
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
+ MEM_freeN(path);
+ }
+ else if (G.debug & G_DEBUG)
+ printf("Button Delete-Key: no path to property\n");
}
- else if (G.debug & G_DEBUG)
- printf("Button Delete-Key: no path to property\n");
}
else if (G.debug & G_DEBUG) {
printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop);
@@ -1858,7 +1894,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
char *path;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
@@ -1869,17 +1905,11 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
if (path) {
if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0);
+ success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h
index 21e85b6fe89..aa56f847f00 100644
--- a/source/blender/editors/armature/BIF_retarget.h
+++ b/source/blender/editors/armature/BIF_retarget.h
@@ -40,7 +40,6 @@ struct bContext;
struct EditBone;
-struct RigJoint;
struct RigGraph;
struct RigNode;
struct RigArc;
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 22aaeccc4a8..59453f0ac71 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -43,6 +43,7 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
+#include "BKE_deform.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -89,7 +90,7 @@ EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length,
bArmature *arm = obedit_arm->data;
EditBone *bone;
- ED_armature_deselect_all(obedit_arm, 0);
+ ED_armature_deselect_all(obedit_arm);
/* Create a bone */
bone = ED_armature_edit_bone_add(arm, "Bone");
@@ -144,7 +145,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
to_root = 1;
}
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* we re-use code for mirror editing... */
flipbone = NULL;
@@ -282,12 +283,8 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
* */
void preEditBoneDuplicate(ListBase *editbones)
{
- EditBone *eBone;
-
/* clear temp */
- for (eBone = editbones->first; eBone; eBone = eBone->next) {
- eBone->temp = NULL;
- }
+ ED_armature_ebone_listbase_temp_clear(editbones);
}
/*
@@ -311,7 +308,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
/* does this constraint have a subtarget in
* this armature?
*/
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -327,8 +324,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
- if (oldtarget->temp) {
- newtarget = (EditBone *) oldtarget->temp;
+ if (oldtarget->temp.ebone) {
+ newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
}
@@ -357,8 +354,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase
/* Copy data from old bone to new bone */
memcpy(eBone, curBone, sizeof(EditBone));
- curBone->temp = eBone;
- eBone->temp = curBone;
+ curBone->temp.ebone = eBone;
+ eBone->temp.ebone = curBone;
if (name != NULL) {
BLI_strncpy(eBone->name, name, sizeof(eBone->name));
@@ -398,13 +395,11 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb
return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
}
-/* previously adduplicate_armature */
static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */
Object *obedit = CTX_data_edit_object(C);
arm = obedit->data;
@@ -419,77 +414,80 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter);
+ if (ebone) {
+ ebone->flag |= BONE_SELECTED;
}
}
}
}
- /* Find the selected bones and duplicate them as needed */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
-
- eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
-
- if (!firstDup)
- firstDup = eBone;
+ /* Find the selected bones and duplicate them as needed */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+ ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
}
}
}
- /* Run though the list and fix the pointers */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = (EditBone *) curBone->temp;
-
- if (!curBone->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- eBone->parent = NULL;
- }
- else if (curBone->parent->temp) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- eBone->parent = (EditBone *)curBone->parent->temp;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- eBone->parent = (EditBone *) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ if (!ebone_iter->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ }
+ else if (ebone_iter->parent->temp.ebone) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ ebone->parent = ebone_iter->parent->temp.ebone;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
*/
- updateDuplicateSubtarget(eBone, arm->edbo, obedit);
+ ebone->parent = (EditBone *) ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
}
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
}
}
/* correct the active bone */
- if (arm->act_edbone) {
- eBone = arm->act_edbone;
- if (eBone->temp)
- arm->act_edbone = eBone->temp;
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
}
- /* Deselect the old bones and select the new ones */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
ED_armature_validate_active(arm);
@@ -515,6 +513,214 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**
+ * near duplicate of #armature_duplicate_selected_exec,
+ * except for parenting part (keep in sync)
+ */
+static int armature_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ bArmature *arm;
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */
+
+ Object *obedit = CTX_data_edit_object(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int axis = 0;
+
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ char name_flip[MAX_VGROUP_NAME];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ if (STREQ(name_flip, ebone_iter->name)) {
+ /* if the name matches, we don't have the potential to be mirrored, just skip */
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip);
+
+ if (ebone) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ /* simple case, we're selected, the other bone isn't! */
+ ebone_iter->temp.ebone = ebone;
+ }
+ else {
+ /* complicated - choose which direction to copy */
+ float axis_delta;
+
+ axis_delta = ebone->head[axis] - ebone_iter->head[axis];
+ if (axis_delta == 0.0f) {
+ axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
+ }
+
+ if (axis_delta == 0.0f) {
+ /* both mirrored bones exist and point to eachother and overlap exactly.
+ *
+ * in this case theres no well defined solution, so de-select both and skip.
+ */
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone_src, *ebone_dst;
+ if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
+ ebone_src = ebone;
+ ebone_dst = ebone_iter;
+ }
+ else {
+ ebone_src = ebone_iter;
+ ebone_dst = ebone;
+ }
+
+ ebone_src->temp.ebone = ebone_dst;
+ ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Find the selected bones and duplicate them as needed, with mirrored name */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED) &&
+ /* 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];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ /* bones must have a side-suffix */
+ if (!STREQ(name_flip, ebone_iter->name)) {
+ EditBone *ebone;
+
+ ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->temp.ebone) {
+ /* copy all flags except for ... */
+ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ /* copy flags incase bone is pre-existing data */
+ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
+
+ if (ebone_iter->parent == NULL) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ else {
+ /* the parent may have been duplicated, if not lookup the mirror parent */
+ EditBone *ebone_parent =
+ (ebone_iter->parent->temp.ebone ?
+ ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent));
+
+ if (ebone_parent == NULL) {
+ /* If the mirror lookup failed, (but the current bone has a parent)
+ * then we can assume the parent has no L/R but is a center bone.
+ * So just use the same parent for both.
+ */
+ ebone_parent = ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+
+ ebone->parent = ebone_parent;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ }
+ }
+
+ transform_armature_mirror_update(obedit);
+
+ /* Selected bones now have their 'temp' pointer set,
+ * so we don't need this anymore */
+
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ /* New bones will be selected, but some of the bones may already exist */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ EditBone *ebone = ebone_iter->temp.ebone;
+ if (ebone && EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
+
+ ED_armature_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+/* following conventions from #MESH_OT_symmetrize */
+void ARMATURE_OT_symmetrize(wmOperatorType *ot)
+{
+ /* subset of 'symmetrize_direction_items' */
+ static EnumPropertyItem arm_symmetrize_direction_items[] = {
+ {-1, "NEGATIVE_X", 0, "-X to +X", ""},
+ {+1, "POSITIVE_X", 0, "+X to -X", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "ARMATURE_OT_symmetrize";
+ ot->description = "Enforce symmetry, make copies of the selection or use existing";
+
+ /* api callbacks */
+ ot->exec = armature_symmetrize_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", arm_symmetrize_direction_items, -1,
+ "Direction", "Which sides to copy from and to (when both are selected)");
+}
+
/* ------------------------------------------ */
/* previously extrude_armature */
@@ -704,7 +910,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
mul_m3_m3m3(totmat, obmat, viewmat);
invert_m3_m3(imat, totmat);
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* Create a bone */
bone = ED_armature_edit_bone_add(obedit->data, name);
@@ -830,7 +1036,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* Properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 88c52989c07..b3297db6176 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -42,6 +42,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -578,6 +579,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
int count;
/* sanity checks */
@@ -610,94 +612,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
float curs[3];
/* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
+ ebp = points.first;
/* Get points - cursor (tail) */
invert_m4_m4(obedit->imat, obedit->obmat);
mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
/* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ newbone = add_points_bone(obedit, ebp->vec, curs);
}
else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
+ EditBonePoint *ebp_a, *ebp_b;
float head[3], tail[3];
short headtail = 0;
/* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
+ {
BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
/* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
}
- else if (ebp->head_owner) {
+ else if (ebp_a->head_owner) {
headtail = 1;
}
- else if (ebp2->head_owner) {
+ else if (ebp_b->head_owner) {
headtail = 2;
}
/* assign head/tail combinations */
if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
}
else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
}
/* add new bone and parent it to the appropriate end */
if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
+ newbone = add_points_bone(obedit, head, tail);
/* do parenting (will need to set connected flag too) */
if (headtail == 2) {
/* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
else
- newbone->parent = ebp->head_owner;
+ newbone->parent = ebp_a->head_owner;
}
else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
else
- newbone->parent = ebp2->head_owner;
+ newbone->parent = ebp_b->head_owner;
}
/* don't set for bone connecting two head points of bones */
- if (ebp->tail_owner || ebp2->tail_owner) {
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
newbone->flag |= BONE_CONNECTED;
}
}
@@ -708,6 +713,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
+
+ if (newbone) {
+ ED_armature_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
@@ -1223,13 +1234,21 @@ void ARMATURE_OT_split(wmOperatorType *ot)
/* ********************************* Delete ******************************* */
+static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
+}
+
/* previously delete_armature */
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
EditBone *curBone, *ebone_next;
- bConstraint *con;
Object *obedit = CTX_data_edit_object(C); // XXX get from context
bool changed = false;
arm = obedit->data;
@@ -1240,48 +1259,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
armature_select_mirrored(arm);
- /* First erase any associated pose channel */
- if (obedit->pose) {
- bPoseChannel *pchan, *pchan_next;
- for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
- curBone = ED_armature_bone_find_name(arm->edbo, pchan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(obedit->pose);
- BLI_freelinkN(&obedit->pose->chanbase, pchan);
- }
- else {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == obedit) {
- if (ct->subtarget[0]) {
- curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
ebone_next = curBone->next;
if (arm->layer & curBone->layer) {
@@ -1319,6 +1298,170 @@ void ARMATURE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_DONE));
+}
+
+static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *ebone, *ebone_next;
+ Object *obedit = CTX_data_edit_object(C);
+ bool changed = false;
+
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
+
+ arm = obedit->data;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
+
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ }
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
+ }
+
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
+ {
+ ebone->temp.ebone = NULL;
+ }
+
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
+ {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ if (ebone->parent &&
+ (ebone->parent->temp.ebone == ebone))
+ {
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
+
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+
+ ED_armature_edit_bone_remove(arm, ebone);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent &&
+ ebone->parent->temp.ebone &&
+ (ebone->flag & BONE_CONNECTED) == 0)
+ {
+ ebone->flag |= BONE_CONNECTED;
+ ebone->rad_head = ebone->parent->rad_head;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (!changed) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_dissolve(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dissolve Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_dissolve";
+ ot->description = "Dissolve selected bones from the armature";
+
+ /* api callbacks */
+ ot->exec = armature_dissolve_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+
/* ********************************* Show/Hide ******************************* */
static int armature_hide_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 2c64c9aa345..2968851f2eb 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -71,7 +71,9 @@ void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
void ARMATURE_OT_delete(struct wmOperatorType *ot);
+void ARMATURE_OT_dissolve(struct wmOperatorType *ot);
void ARMATURE_OT_duplicate(struct wmOperatorType *ot);
+void ARMATURE_OT_symmetrize(struct wmOperatorType *ot);
void ARMATURE_OT_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
@@ -233,6 +235,7 @@ EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
void armature_tag_select_mirrored(struct bArmature *arm);
+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);
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index a8b5f888597..eedff896315 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -104,7 +104,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
@@ -270,7 +270,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
// XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
{
- BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
+ BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname);
}
/* correct view locking */
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index c80953d6737..e7f036f6911 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -65,7 +65,9 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
WM_operatortype_append(ARMATURE_OT_delete);
+ WM_operatortype_append(ARMATURE_OT_dissolve);
WM_operatortype_append(ARMATURE_OT_duplicate);
+ WM_operatortype_append(ARMATURE_OT_symmetrize);
WM_operatortype_append(ARMATURE_OT_extrude);
WM_operatortype_append(ARMATURE_OT_hide);
WM_operatortype_append(ARMATURE_OT_reveal);
@@ -265,8 +267,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0);
@@ -275,7 +278,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0);
/* set flags */
WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
@@ -411,5 +414,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
/* menus */
WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0);
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 53989dd783c..8cda6f6db77 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -78,7 +78,7 @@ static void joined_armature_fix_links_constraints(
bConstraint *con;
for (con = lb->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -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_copy_animdata(base->object->adt, false);
+ ob->adt = BKE_animdata_copy(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_copy_animdata(curarm->adt, false);
+ arm->adt = BKE_animdata_copy(curarm->adt, false);
}
else {
/* merge in data - we'll fix the drivers manually */
@@ -435,7 +435,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -473,7 +473,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -548,7 +548,7 @@ static void separate_armature_bones(Object *ob, short sel)
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
- ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->temp.p = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
ebo->flag &= ~BONE_CONNECTED;
}
}
@@ -641,6 +641,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
ED_armature_to_edit(obedit->data);
+ /* parents tips remain selected when connected children are removed. */
+ ED_armature_deselect_all(obedit);
+
BKE_report(op->reports, RPT_INFO, "Separated bones");
/* note, notifier might evolve */
@@ -660,6 +663,7 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature";
/* callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 581dd00e285..5aa2c628252 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -54,9 +54,9 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
-#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (GET_INT_FROM_POINTER((ebone)->temp)))
-#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp = SET_INT_IN_POINTER(val))
+/* utility macros for storing a temp int in the bone (selection flag) */
+#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
+#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
@@ -388,61 +388,14 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
return NULL;
}
-
-
-/* toggle==0: deselect
- * toggle==1: swap (based on test)
- * toggle==2: swap (no test), CURRENTLY UNUSED
- */
-void ED_armature_deselect_all(Object *obedit, int toggle)
+void ED_armature_deselect_all(Object *obedit)
{
bArmature *arm = obedit->data;
- EditBone *eBone;
- int sel = 1;
-
- if (toggle == 1) {
- /* Determine if there are any selected bones
- * and therefore whether we are selecting or deselecting */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- // if (arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- sel = 0;
- break;
- }
- // }
- }
- }
- else {
- sel = toggle;
- }
+ EditBone *ebone;
- /* Set the flags */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (sel == 2) {
- /* invert selection of bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
- else if (sel == 1) {
- /* select bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
-
- ED_armature_sync_selection(arm->edbo);
}
void ED_armature_deselect_all_visible(Object *obedit)
@@ -489,8 +442,9 @@ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect,
nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
if (nearBone) {
- if (!extend && !deselect && !toggle)
- ED_armature_deselect_all(obedit, 0);
+ if (!extend && !deselect && !toggle) {
+ ED_armature_deselect_all(obedit);
+ }
/* by definition the non-root connected bones have no root point drawn,
* so a root selection needs to be delivered to the parent tip */
@@ -731,7 +685,7 @@ static void armature_select_more_less(Object *ob, bool more)
}
}
}
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
ED_armature_sync_selection(arm->edbo);
@@ -962,75 +916,78 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
/* ********************* select hierarchy operator ************** */
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
-{
- EditBone *curbone, *chbone = NULL;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
- chbone = curbone;
- }
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Object *ob;
bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
+ EditBone *ebone_active;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
ob = obedit;
arm = (bArmature *)ob->data;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- /* only work on bone if it is visible and its selection can change */
- if (EBONE_SELECTABLE(arm, curbone)) {
- if (curbone == arm->act_edbone) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = pabone;
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- }
-
+
+ ebone_active = arm->act_edbone;
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (ebone_active->parent) {
+ EditBone *ebone_parent;
+
+ ebone_parent = ebone_active->parent;
+
+ if (EBONE_SELECTABLE(arm, ebone_parent)) {
+ arm->act_edbone = ebone_parent;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
}
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(arm, curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_SELECTABLE(arm, chbone)) {
- chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = chbone;
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ ED_armature_ebone_select_set(ebone_parent, true);
+
+ changed = true;
+ }
+ }
+
+ }
+ else { /* BONE_SELECT_CHILD */
+ EditBone *ebone_iter, *ebone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (EBONE_SELECTABLE(arm, ebone_iter)) {
+ if (ebone_iter->parent == ebone_active) {
+ if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
+ ebone_child = ebone_iter;
+ break;
}
- break;
}
}
}
}
+
+ if (ebone_child) {
+ arm->act_edbone = ebone_child;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
+ }
+ ED_armature_ebone_select_set(ebone_child, true);
+
+ changed = true;
+ }
}
+ if (changed == false) {
+ return OPERATOR_CANCELLED;
+ }
+
ED_armature_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 97f69d86aee..09284860ec4 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -276,18 +276,19 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo)
/* helper function for tools to work on mirrored parts.
* it leaves mirrored bones selected then too, which is a good indication of what happened */
-void armature_select_mirrored(bArmature *arm)
+void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
+ BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
EditBone *curBone, *ebone_mirr;
for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
+ if (curBone->flag & flag) {
ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
if (ebone_mirr)
- ebone_mirr->flag |= BONE_SELECTED;
+ ebone_mirr->flag |= (curBone->flag & flag);
}
}
}
@@ -295,6 +296,11 @@ void armature_select_mirrored(bArmature *arm)
}
+void armature_select_mirrored(bArmature *arm)
+{
+ armature_select_mirrored_ex(arm, BONE_SELECTED);
+}
+
void armature_tag_select_mirrored(bArmature *arm)
{
EditBone *curBone;
@@ -488,7 +494,7 @@ static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
/* Find the associated editbone */
for (ebone = editbonelist->first; ebone; ebone = ebone->next)
- if ((Bone *)ebone->temp == curBone)
+ if (ebone->temp.bone == curBone)
break;
if (ebone) {
@@ -548,7 +554,7 @@ void ED_armature_from_edit(bArmature *arm)
/* Copy the bones from the editData into the armature */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp = newBone; /* Associate the real Bones with the EditBones */
+ eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
copy_v3_v3(newBone->arm_head, eBone->head);
@@ -584,9 +590,9 @@ void ED_armature_from_edit(bArmature *arm)
/* Fix parenting in a separate pass to ensure ebone->bone connections
* are valid at this point */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = (Bone *)eBone->temp;
+ newBone = eBone->temp.bone;
if (eBone->parent) {
- newBone->parent = (Bone *)eBone->parent->temp;
+ newBone->parent = eBone->parent->temp.bone;
BLI_addtail(&newBone->parent->childbase, newBone);
{
@@ -695,24 +701,24 @@ static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
if (ebone_dst->prop) {
ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop);
}
- ebone_src->temp = ebone_dst;
+ ebone_src->temp.ebone = ebone_dst;
BLI_addtail(lb_dst, ebone_dst);
}
/* set pointers */
for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) {
if (ebone_dst->parent) {
- ebone_dst->parent = ebone_dst->parent->temp;
+ ebone_dst->parent = ebone_dst->parent->temp.ebone;
}
}
}
-static void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
+void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
{
EditBone *ebone;
/* be sure they don't hang ever */
for (ebone = lb->first; ebone; ebone = ebone->next) {
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
}
@@ -733,7 +739,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
/* active bone */
if (uarm->act_edbone) {
ebone = uarm->act_edbone;
- arm->act_edbone = ebone->temp;
+ arm->act_edbone = ebone->temp.ebone;
}
else {
arm->act_edbone = NULL;
@@ -755,7 +761,7 @@ static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
/* active bone */
if (arm->act_edbone) {
ebone = arm->act_edbone;
- uarm->act_edbone = ebone->temp;
+ uarm->act_edbone = ebone->temp.ebone;
}
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 5376fc8c79b..2235f9f92cc 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -707,7 +707,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -832,7 +832,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index b7d14e089cf..c630ea6478a 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -127,12 +127,12 @@ struct LaplacianSystem {
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
{
- void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
+ void **p;
- if (p)
+ if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p))
*p = (void *)((intptr_t)*p + (intptr_t)1);
else
- BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1);
+ *p = (void *)((intptr_t)1);
}
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
@@ -1719,7 +1719,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
/* sanity check */
for (b = 0; b < mdb->size3; b++)
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
+ if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
printf("totalphi deficiency [%s|%d] %d: %.10f\n",
(mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
#endif
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index 820aedc5467..1412136c1a8 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -29,11 +29,9 @@
//#define RIGID_DEFORM
-struct Scene;
struct Object;
struct Mesh;
struct bDeformGroup;
-struct MeshDeformModifierData;
#ifdef RIGID_DEFORM
struct EditMesh;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 549a3854bac..e87c324d7ec 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -436,7 +436,7 @@ static void pose_copy_menu(Scene *scene)
pchan->constflag |= pchanact->constflag;
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
break;
case 6: /* Transform Locks */
@@ -550,7 +550,7 @@ static void pose_copy_menu(Scene *scene)
BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
@@ -862,7 +862,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- layers[bit] = (pchan->bone->layer & (1 << bit)) != 0;
+ layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
}
}
CTX_DATA_END;
@@ -936,8 +936,9 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1 << bit))
+ if (ebone->layer & (1u << bit)) {
layers[bit] = 1;
+ }
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 413a74d24b5..4d9df06f33f 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -130,6 +130,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
{
Object *ob = ED_pose_object_from_context(C);
bPose *pose;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
uiPopupMenu *pup;
uiLayout *layout;
@@ -140,6 +141,17 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose = ob->pose;
+
+ /* If group index is set, try to use it! */
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int num_groups = BLI_listbase_count(&pose->agroups);
+ const int group = RNA_property_int_get(op->ptr, prop);
+
+ /* just use the active group index, and call the exec callback for the calling operator */
+ if (group > 0 && group <= num_groups) {
+ return op->type->exec(C, op);
+ }
+ }
/* if there's no active group (or active is invalid), create a new menu to find it */
if (pose->active_group <= 0) {
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 5d5a9bf363c..44470c1f827 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -62,7 +62,7 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
+/* utility macros for storing a temp int in the bone (selection flag) */
#define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp)))
#define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val))
@@ -458,7 +458,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
{
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = ob->data;
- Bone *curbone, *pabone, *chbone;
+ bPoseChannel *pchan_act;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
- bool found = false;
+ bool changed = false;
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- curbone = pchan->bone;
-
- if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
- if (curbone == arm->act_bone) {
- if (direction == BONE_SELECT_PARENT) {
- if (pchan->parent == NULL) continue;
- else pabone = pchan->parent->bone;
-
- if (PBONE_SELECTABLE(arm, pabone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- pabone->flag |= BONE_SELECTED;
- arm->act_bone = pabone;
-
- found = 1;
- break;
- }
+ pchan_act = BKE_pose_channel_active(ob);
+ if (pchan_act == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan_act->parent) {
+ Bone *bone_parent;
+ bone_parent = pchan_act->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, bone_parent)) {
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
}
- else { /* direction == BONE_SELECT_CHILD */
- /* the child member is only assigned to connected bones, see [#30340] */
-#if 0
- if (pchan->child == NULL) continue;
- else chbone = pchan->child->bone;
-#else
- /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
- chbone = pchan->child ? pchan->child->bone : NULL;
- if (chbone == NULL) {
- bPoseChannel *pchan_child;
-
- for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
- if (pchan_child->parent == pchan) {
- chbone = pchan_child->bone;
- break;
- }
- }
- }
- }
+ bone_parent->flag |= BONE_SELECTED;
+ arm->act_bone = bone_parent;
- if (chbone == NULL) continue;
-#endif
-
- if (PBONE_SELECTABLE(arm, chbone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- chbone->flag |= BONE_SELECTED;
- arm->act_bone = chbone;
-
- found = 1;
- break;
+ changed = true;
+ }
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ bPoseChannel *pchan_iter;
+ Bone *bone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
+ for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
+ if (pchan_iter->parent == pchan_act) {
+ if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
+ bone_child = pchan_iter->bone;
+ break;
+ }
}
}
}
}
+
+ if (bone_child) {
+ arm->act_bone = bone_child;
+
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
+ }
+ bone_child->flag |= BONE_SELECTED;
+
+ changed = true;
+ }
}
- CTX_DATA_END;
- if (found == 0)
+ if (changed == false) {
return OPERATOR_CANCELLED;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -825,7 +821,7 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
break;
default:
- printf("pose_select_grouped() - Unknown selection type %d\n", type);
+ printf("pose_select_grouped() - Unknown selection type %u\n", type);
break;
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 5f9f24d23a4..d583fd864b0 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -43,6 +43,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_unit.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -53,6 +54,7 @@
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "armature_intern.h"
@@ -98,6 +100,8 @@ typedef struct tPoseSlideOp {
int flag; /* unused for now, but can later get used for storing runtime settings.... */
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
+
+ NumInput num; /* numeric input */
} tPoseSlideOp;
/* Pose Sliding Modes */
@@ -154,6 +158,12 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
*/
BLI_dlrbTree_init(&pso->keys);
+ /* initialise numeric input */
+ initNumInput(&pso->num);
+ pso->num.idx_max = 0; /* one axis */
+ pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
+ pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+
/* return status is whether we've got all the data we were requested to get */
return 1;
}
@@ -201,6 +211,12 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
/* next/end */
eVal = evaluate_fcurve(fcu, (float)pso->nextFrame);
+ /* if both values are equal, don't do anything */
+ if (IS_EQF(sVal, eVal)) {
+ (*val) = sVal;
+ return;
+ }
+
/* calculate the relative weights of the endpoints */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* get weights from the percentage control */
@@ -234,7 +250,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
}
@@ -247,7 +263,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
}
@@ -320,6 +336,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
if (prop) {
switch (RNA_property_type(prop)) {
+ /* continuous values that can be smoothly interpolated... */
case PROP_FLOAT:
{
float tval = RNA_property_float_get(&ptr, prop);
@@ -327,8 +344,6 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_float_set(&ptr, prop, tval);
break;
}
- case PROP_BOOLEAN:
- case PROP_ENUM:
case PROP_INT:
{
float tval = (float)RNA_property_int_get(&ptr, prop);
@@ -336,6 +351,23 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_int_set(&ptr, prop, (int)tval);
break;
}
+
+ /* values which can only take discrete values */
+ case PROP_BOOLEAN:
+ {
+ float tval = (float)RNA_property_boolean_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, &tval);
+ RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
+ break;
+ }
+ case PROP_ENUM:
+ {
+ /* don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between
+ */
+ break;
+ }
+
default:
/* cannot handle */
//printf("Cannot Pose Slide non-numerical property\n");
@@ -404,11 +436,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
}
else if (pso->mode == POSESLIDE_PUSH) {
float quat_diff[4], quat_orig[4];
-
+
/* calculate the delta transform from the previous to the current */
/* TODO: investigate ways to favour one transform more? */
sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);
-
+
/* make a copy of the original rotation */
copy_qt_qt(quat_orig, pchan->quat);
@@ -418,7 +450,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
else {
float quat_interp[4], quat_orig[4];
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
/* perform this blending several times until a satisfactory result is reached */
while (iters-- > 0) {
/* calculate the interpolation between the endpoints */
@@ -512,7 +544,7 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* draw percentage indicator in header */
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[32];
+ char status_str[256];
char mode_str[32];
switch (pso->mode) {
@@ -532,7 +564,18 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ 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);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ }
+
ED_area_headerprint(pso->sa, status_str);
}
@@ -617,6 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
case LEFTMOUSE: /* confirm */
@@ -656,25 +700,54 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: /* calculate new position */
{
- /* calculate percentage based on position of mouse (we only use x-axis for now.
- * since this is more convenient for users to do), and store new percentage value
- */
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- 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);
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* calculate percentage based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new percentage value
+ */
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ 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);
+ }
break;
}
- default: /* unhandled event (maybe it was some view manip? */
- /* allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ default:
+ if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
+ float value;
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float
+ */
+ value = pso->percentage * 100.0f;
+ applyNumInput(&pso->num, &value);
+
+ pso->percentage = value / 100.0f;
+ 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);
+ break;
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
/* still running... */
@@ -898,6 +971,8 @@ typedef enum ePosePropagate_Termination {
/* stop when we run out of keyframes */
POSE_PROPAGATE_BEFORE_END,
+ /* only do on keyframes that are selected */
+ POSE_PROPAGATE_SELECTED_KEYS,
/* only do on the frames where markers are selected */
POSE_PROPAGATE_SELECTED_MARKERS
} ePosePropagate_Termination;
@@ -1098,13 +1173,20 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
* since it may be as of yet unkeyed
* - if starting before the starting frame, don't touch the key, as it may have had some valid
* values
+ * - if only doing selected keyframes, start from the first one
*/
- match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
-
- if (fcu->bezt[match].vec[1][0] < startFrame)
- i = match + 1;
- else
- i = match;
+ if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
+ match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+
+ if (fcu->bezt[match].vec[1][0] < startFrame)
+ i = match + 1;
+ else
+ i = match;
+ }
+ else {
+ /* selected - start from first keyframe */
+ i = 0;
+ }
for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
/* additional termination conditions based on the operator 'mode' property go here... */
@@ -1137,6 +1219,11 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
if (ce == NULL)
continue;
}
+ else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
+ /* only allow if this keyframe is already selected - skip otherwise */
+ if (BEZSELECTED(bezt) == 0)
+ continue;
+ }
/* just flatten handles, since values will now be the same either side... */
/* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
@@ -1219,12 +1306,20 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
void POSE_OT_propagate(wmOperatorType *ot)
{
static EnumPropertyItem terminate_items[] = {
- {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
- {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", "Propagate pose to first keyframe following the current frame only"},
- {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
- {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"},
- {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", "Propagate pose to all keyframes from current frame until no more are found"},
- {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
+ {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held",
+ "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
+ {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe",
+ "Propagate pose to first keyframe following the current frame only"},
+ {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe",
+ "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
+ {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame",
+ "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe",
+ "Propagate pose to all keyframes from current frame until no more are found"},
+ {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes",
+ "Propagate pose to all selected keyframes"},
+ {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers",
+ "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index fbf6dccdb38..01e16df9f08 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -320,7 +320,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
if (selOnly)
paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
else
- paste_ok = ((pchan != NULL));
+ paste_ok = (pchan != NULL);
/* continue? */
if (paste_ok) {
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 0b449c4334d..1b877c0fba9 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -38,7 +38,6 @@ set(SRC
editcurve.c
editcurve_add.c
editfont.c
- lorem.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index d54db77754f..579f149ea8b 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -38,9 +38,6 @@ struct EditNurb;
struct Object;
struct wmOperatorType;
-/* lorem.c */
-extern const char ED_lorem[];
-
/* editfont.c */
enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
enum { CASE_LOWER, CASE_UPPER };
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 0f42dc923a4..4bcb16d31ef 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -54,7 +54,6 @@ void ED_operatortypes_curve(void)
{
WM_operatortype_append(FONT_OT_text_insert);
WM_operatortype_append(FONT_OT_line_break);
- WM_operatortype_append(FONT_OT_insert_lorem);
WM_operatortype_append(FONT_OT_case_toggle);
WM_operatortype_append(FONT_OT_case_set);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 936a40b83b6..1a10814bbf1 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -327,17 +327,17 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
editnurb->keyindex = gh;
}
-static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_lookup(editnurb->keyindex, cv);
}
-static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
}
-static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt)
+static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
{
CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
@@ -370,7 +370,7 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
return index->key_index;
}
-static void keyIndex_delCV(EditNurb *editnurb, void *cv)
+static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
{
if (!editnurb->keyindex) {
return;
@@ -398,7 +398,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
+ const BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
@@ -407,7 +407,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
}
else {
- BPoint *bp = nu->bp;
+ const BPoint *bp = nu->bp;
a = nu->pntsu * nu->pntsv;
while (a--) {
@@ -1188,7 +1188,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert)
while (a--) {
keyIndex = getCVKeyIndex(editnurb, bezt);
- if (keyIndex) {
+ if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
if (keyIndex->switched) {
old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
@@ -1538,6 +1538,7 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->description = "Separate selected points from connected unselected points into a new object";
/* api callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_exec;
ot->poll = ED_operator_editsurfcurve;
@@ -2526,7 +2527,7 @@ void CURVE_OT_radius_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
}
/********************* smooth operator ********************/
@@ -3746,7 +3747,7 @@ void CURVE_OT_subdivide(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -4881,8 +4882,9 @@ void CURVE_OT_spin(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f);
+ RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Center", "Center in global view space", -1000.0f, 1000.0f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
/***************** extrude vertex operator **********************/
@@ -5351,7 +5353,8 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Location to add new vertex at", -1e4, 1e4);
+ RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Location", "Location to add new vertex at", -1.0e4f, 1.0e4f);
}
/***************** extrude operator **********************/
@@ -6136,13 +6139,14 @@ void CURVE_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
+ RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
WM_operator_properties_select_action_simple(ot, SEL_SELECT);
}
/********************* every nth number of point *******************/
-static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
+static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset)
{
int a, start;
@@ -6151,7 +6155,8 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
bezt = &nu->bezt[a - 1];
while (a--) {
- if (abs(start - a) % nth) {
+ const int depth = abs(start - a);
+ if ((offset + depth) % (skip + nth) >= skip) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
}
@@ -6159,10 +6164,10 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
}
}
-static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
+static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
{
int a, startrow, startpnt;
- int dist, row, pnt;
+ int row, pnt;
startrow = (bp - nu->bp) / nu->pntsu;
startpnt = (bp - nu->bp) % nu->pntsu;
@@ -6173,8 +6178,8 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
pnt = nu->pntsu - 1;
while (a--) {
- dist = abs(pnt - startpnt) + abs(row - startrow);
- if (dist % nth) {
+ const int depth = abs(pnt - startpnt) + abs(row - startrow);
+ if ((offset + depth) % (skip + nth) >= skip) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
}
@@ -6188,7 +6193,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
}
}
-bool ED_curve_select_nth(Curve *cu, int nth)
+bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
{
Nurb *nu = NULL;
void *vert = NULL;
@@ -6197,10 +6202,10 @@ bool ED_curve_select_nth(Curve *cu, int nth)
return false;
if (nu->bezt) {
- select_nth_bezt(nu, vert, nth);
+ select_nth_bezt(nu, vert, nth, skip, offset);
}
else {
- select_nth_bp(nu, vert, nth);
+ select_nth_bp(nu, vert, nth, skip, offset);
}
return true;
@@ -6209,9 +6214,14 @@ bool ED_curve_select_nth(Curve *cu, int nth)
static int select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- int nth = RNA_int_get(op->ptr, "nth");
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
+ int offset = RNA_int_get(op->ptr, "offset");
+
+ /* so input of offset zero ends up being (nth - 1) */
+ offset = mod_i(offset, nth + skip);
- if (!ED_curve_select_nth(obedit->data, nth)) {
+ if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) {
if (obedit->type == OB_SURF) {
BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
}
@@ -6242,6 +6252,8 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
+ RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
}
/********************** add duplicate operator *********************/
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 7c53896b969..555a53ae532 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -121,7 +121,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
const float grid = 1.0f;
const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
const int stype = (type & CU_PRIMITIVE);
- const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */
+ const bool force_3d = (((Curve *)obedit->data)->flag & CU_3D) != 0; /* could be adding to an existing 3D curve */
unit_m4(umat);
unit_m4(viewmat);
@@ -488,9 +488,10 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
if (!isSurf) { /* adding curve */
if (obedit == NULL || obedit->type != OB_CURVE) {
+ const char *name = get_curve_defname(type);
Curve *cu;
- obedit = ED_object_add_type(C, OB_CURVE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_CURVE, name, loc, rot, true, layer);
newob = true;
cu = (Curve *)obedit->data;
@@ -505,7 +506,8 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
else { /* adding surface */
if (obedit == NULL || obedit->type != OB_SURF) {
- obedit = ED_object_add_type(C, OB_SURF, loc, rot, true, layer);
+ const char *name = get_surf_defname(type);
+ obedit = ED_object_add_type(C, OB_SURF, name, loc, rot, true, layer);
newob = true;
}
else {
@@ -513,18 +515,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- /* rename here, the undo stack checks name for valid undo pushes */
- if (newob) {
- if (obedit->type == OB_CURVE) {
- rename_id((ID *)obedit, get_curve_defname(type));
- rename_id((ID *)obedit->data, get_curve_defname(type));
- }
- else {
- rename_id((ID *)obedit, get_surf_defname(type));
- rename_id((ID *)obedit->data, get_surf_defname(type));
- }
- }
-
/* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
if (newob && enter_editmode)
ED_undo_push(C, "Enter Editmode");
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 8393acc6919..dd807828d9d 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -275,57 +275,6 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
-/********************** insert lorem operator *********************/
-
-static int insert_lorem_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- const char *p, *p2;
- int i;
- static const char *lastlorem = NULL;
-
- if (lastlorem)
- p = lastlorem;
- else
- p = ED_lorem;
-
- i = rand() / (RAND_MAX / 6) + 4;
-
- for (p2 = p; *p2 && i; p2++) {
- insert_into_textbuf(obedit, *p2);
-
- if (*p2 == '.')
- i--;
- }
-
- lastlorem = p2 + 1;
- if (strlen(lastlorem) < 5)
- lastlorem = ED_lorem;
-
- insert_into_textbuf(obedit, '\n');
- insert_into_textbuf(obedit, '\n');
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void FONT_OT_insert_lorem(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Insert Lorem";
- ot->description = "Insert placeholder text";
- ot->idname = "FONT_OT_insert_lorem";
-
- /* api callbacks */
- ot->exec = insert_lorem_exec;
- ot->poll = ED_operator_editfont;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* -------------------------------------------------------------------- */
/* Generic Paste Functions */
@@ -577,7 +526,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
int a;
float rot[3] = {0.f, 0.f, 0.f};
- obedit = BKE_object_add(bmain, scene, OB_FONT);
+ obedit = BKE_object_add(bmain, scene, OB_FONT, NULL);
base = scene->basact;
/* seems to assume view align ? TODO - look into this, could be an operator option */
@@ -1417,7 +1366,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
accentcode = 0;
}
else if (event->utf8_buf[0]) {
- BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 2);
+ inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf);
ascii = inserted_text[0];
insert_into_textbuf(obedit, ascii);
accentcode = 0;
diff --git a/source/blender/editors/curve/lorem.c b/source/blender/editors/curve/lorem.c
deleted file mode 100644
index 59bf3f50dbc..00000000000
--- a/source/blender/editors/curve/lorem.c
+++ /dev/null
@@ -1,658 +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.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/curve/lorem.c
- * \ingroup edcurve
- */
-
-
-#include "BLI_sys_types.h"
-#include "curve_intern.h"
-
-const char ED_lorem[] = {
-76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99,
-111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 101, 108, 105, 116, 46, 32, 65, 108, 105,
-113, 117, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 116, 111, 114, 116, 111, 114, 32, 110, 111, 110, 32, 101, 117, 105, 115, 109, 111, 100, 32,
-118, 97, 114, 105, 117, 115, 44, 32, 110, 117, 108, 108, 97, 32, 111, 100, 105, 111, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 117, 108, 108, 97,
-44, 32, 97, 116, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 108, 111, 114, 101, 109, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 110, 117,
-108, 108, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 97, 116, 32, 112, 101, 100,
-101, 32, 98, 108, 97, 110, 100, 105, 116, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105,
-115, 113, 117, 101, 32, 105, 112, 115, 117, 109, 32, 110, 101, 99, 32, 101, 110, 105, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 110, 117, 110, 99, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 99, 117,
-114, 115, 117, 115, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 113, 117, 105, 115, 32, 100, 117, 105, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 116, 101, 109, 112, 111, 114, 44, 32, 97, 114, 99, 117,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 44, 32, 116, 111, 114, 116,
-111, 114, 32, 119, 105, 115, 105, 32, 100, 97, 112, 105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100, 32, 111, 114, 110, 97, 114,
-101, 32, 102, 101, 108, 105, 115, 32, 105, 112, 115, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 99, 117, 114, 115, 117, 115, 46, 32, 86, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 116, 44, 32, 99,
-111, 110, 118, 97, 108, 108, 105, 115, 32, 101, 117, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 116, 44, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 78, 117, 108, 108, 97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117,
-110, 99, 32, 101, 116, 32, 109, 97, 117, 114, 105, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 115, 116, 32, 98, 105, 98, 101, 110,
-100, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101,
-32, 108, 105, 98, 101, 114, 111, 32, 101, 117, 32, 110, 105, 115, 108, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103,
-101, 116, 32, 108, 105, 98, 101, 114, 111, 46, 32, 68, 111, 110, 101, 99, 32, 116, 101, 109, 112, 117, 115, 32, 105, 112, 115, 117, 109, 32, 115, 101,
-100, 32, 113, 117, 97, 109, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105, 115, 32, 101, 110,
-105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 101, 99, 116, 117, 115, 32, 100, 105, 97, 109, 44, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 105, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 73, 110, 32, 99, 111, 110, 103, 117, 101, 32, 109, 97, 103, 110, 97,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 117, 114, 110, 97, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 97, 117, 103, 117, 101, 32, 115,
-101, 100, 32, 110, 105, 115, 108, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 67, 117, 109, 32, 115, 111, 99, 105,
-105, 115, 32, 110, 97, 116, 111, 113, 117, 101, 32, 112, 101, 110, 97, 116, 105, 98, 117, 115, 32, 101, 116, 32, 109, 97, 103, 110, 105, 115, 32, 100,
-105, 115, 32, 112, 97, 114, 116, 117, 114, 105, 101, 110, 116, 32, 109, 111, 110, 116, 101, 115, 44, 32, 110, 97, 115, 99, 101, 116, 117, 114, 32, 114,
-105, 100, 105, 99, 117, 108, 117, 115, 32, 109, 117, 115, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 108, 108, 97, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 97, 112, 105, 101, 110,
-32, 101, 116, 32, 113, 117, 97, 109, 46, 32, 78, 117, 110, 99, 32, 97, 99, 32, 109, 97, 103, 110, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115,
-32, 116, 101, 108, 108, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 67, 114, 97, 115, 32,
-97, 117, 103, 117, 101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 109, 97, 116, 116, 105, 115, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 102,
-101, 114, 109, 101, 110, 116, 117, 109, 32, 97, 116, 44, 32, 115, 101, 109, 112, 101, 114, 32, 97, 99, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-67, 114, 97, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 115, 101, 109, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 105, 97, 99, 117, 108, 105, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110,
-116, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 102, 101, 108, 105, 115, 46, 32, 85, 116, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117,
-114, 105, 115, 32, 117, 114, 110, 97, 46, 32, 85, 116, 32, 101, 117, 32, 101, 110, 105, 109, 32, 101, 117, 32, 97, 110, 116, 101, 32, 112, 111, 114,
-116, 97, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 32, 101, 115, 116, 32, 97, 99, 32, 102, 101, 108, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 117, 99, 116,
-111, 114, 46, 32, 78, 117, 110, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111,
-114, 101, 101, 116, 32, 97, 110, 116, 101, 32, 101, 116, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 102, 101, 117, 103, 105, 97, 116,
-32, 97, 114, 99, 117, 32, 101, 103, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 111, 114, 98, 105, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32,
-116, 111, 114, 116, 111, 114, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 117, 115, 32, 97,
-114, 99, 117, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 118, 101, 108, 44,
-32, 112, 111, 115, 117, 101, 114, 101, 32, 105, 100, 44, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110, 32, 99, 111, 109, 109, 111, 100, 111, 32,
-103, 114, 97, 118, 105, 100, 97, 32, 115, 101, 109, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118,
-101, 104, 105, 99, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 119, 105, 115, 105, 46, 32,
-77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 116, 101, 108, 108, 117, 115, 32, 101, 117, 32, 115, 97, 112, 105, 101,
-110, 46, 32, 78, 117, 110, 99, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97,
-98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 65, 101, 110, 101, 97, 110, 32,
-100, 105, 99, 116, 117, 109, 32, 110, 101, 113, 117, 101, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 101, 114, 97, 116, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114,
-105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32,
-83, 101, 100, 32, 106, 117, 115, 116, 111, 32, 116, 117, 114, 112, 105, 115, 44, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 117, 116,
-44, 32, 109, 97, 116, 116, 105, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 111, 114, 110, 97, 114, 101, 32, 114, 117, 116, 114, 117, 109,
-44, 32, 109, 97, 115, 115, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 101, 110, 105,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 101, 108, 108, 117, 115,
-32, 105, 112, 115, 117, 109, 44, 32, 108, 117, 99, 116, 117, 115, 32, 117, 116, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 111, 110, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 104,
-97, 115, 101, 108, 108, 117, 115, 32, 108, 97, 99, 105, 110, 105, 97, 32, 119, 105, 115, 105, 32, 97, 116, 32, 101, 115, 116, 46, 32, 68, 111, 110,
-101, 99, 32, 101, 108, 105, 116, 32, 119, 105, 115, 105, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 110, 111, 110, 44, 32, 112, 108, 97, 99, 101,
-114, 97, 116, 32, 105, 110, 44, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 105, 100, 44, 32, 101, 108, 105, 116, 46, 32, 78, 117, 110, 99,
-32, 100, 111, 108, 111, 114, 32, 100, 111, 108, 111, 114, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 44, 32, 98, 105, 98,
-101, 110, 100, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 108, 97, 99, 105, 110, 105, 97, 32, 105, 100, 44, 32, 101, 114, 97, 116, 46, 32, 67,
-114, 97, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 111, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 67, 114, 97, 115, 32, 111, 114, 99, 105, 46, 32,
-80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 97, 115, 115, 97, 32, 117, 114, 110, 97, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 115, 101,
-109, 112, 101, 114, 44, 32, 97, 117, 99, 116, 111, 114, 32, 97, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 116,
-101, 108, 108, 117, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 111, 114, 98, 105,
-32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 97, 109, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 118, 101, 110, 101, 110, 97, 116, 105,
-115, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 97, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 117, 44, 32, 101, 115, 116, 46, 32, 78, 117,
-110, 99, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 108, 101, 99, 116, 117, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 108, 105, 98, 101,
-114, 111, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 108,
-105, 103, 117, 108, 97, 46, 32, 78, 117, 110, 99, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 114,
-99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 113, 117, 97, 109, 32, 97, 116, 32, 109, 97, 115, 115,
-97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32, 109, 97, 117, 114, 105,
-115, 46, 32, 73, 110, 32, 105, 100, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105,
-117, 115, 32, 105, 112, 115, 117, 109, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115, 99, 101, 32, 109, 97, 117, 114, 105, 115, 32, 108,
-97, 99, 117, 115, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 113, 117, 105,
-115, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 117, 99, 116, 117, 115, 44, 32, 112, 101, 100, 101, 46, 32, 83, 101, 100, 32, 119, 105,
-115, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 109, 97, 116, 116, 105, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32,
-104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 101, 109, 32, 110, 101, 99, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 105,
-100, 32, 113, 117, 97, 109, 46, 32, 67, 114, 97, 115, 32, 110, 101, 99, 32, 109, 97, 117, 114, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114,
-32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 100, 117, 105, 32, 115, 101, 109, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32,
-115, 101, 100, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 99, 117, 114, 115, 117, 115, 32, 105, 110, 44, 32, 109, 97,
-103, 110, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 110, 101, 113, 117, 101, 32, 108, 97, 99, 117, 115, 44, 32, 99, 111, 110, 115, 101, 99, 116,
-101, 116, 117, 101, 114, 32, 110, 101, 99, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 101, 103, 101, 116, 44, 32, 100, 117, 105, 46, 32, 70, 117, 115, 99, 101, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46,
-32, 68, 111, 110, 101, 99, 32, 110, 101, 99, 32, 116, 101, 108, 108, 117, 115, 32, 113, 117, 105, 115, 32, 108, 101, 111, 32, 108, 111, 98, 111, 114,
-116, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 69, 116, 105, 97, 109, 32, 109, 101, 116, 117, 115, 32, 117, 114, 110,
-97, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44,
-32, 99, 117, 114, 115, 117, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 77, 111, 114, 98, 105, 32, 98, 105, 98, 101, 110, 100,
-117, 109, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 99, 116, 117, 115, 46, 32, 83, 101, 100, 32, 110, 111, 110, 32, 97, 110, 116, 101,
-32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 101, 109, 112, 111, 114, 46,
-32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 32, 105, 110, 32, 115, 101, 109, 32, 116, 101, 109, 112, 111, 114, 32,
-105, 109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 118, 101, 108, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32,
-110, 105, 98, 104, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115,
-113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105,
-97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115,
-46, 32, 83, 101, 100, 32, 118, 101, 108, 32, 108, 101, 111, 32, 110, 101, 99, 32, 101, 114, 111, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 105,
-109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 100, 117, 105, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97,
-32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 106, 117, 115, 116, 111, 32, 112, 117, 114, 117, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114,
-112, 101, 114, 32, 108, 105, 103, 117, 108, 97, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 100,
-111, 108, 111, 114, 32, 101, 110, 105, 109, 32, 105, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 101, 108, 101, 109, 101, 110, 116,
-117, 109, 44, 32, 112, 101, 100, 101, 32, 101, 103, 101, 116, 32, 112, 111, 114, 116, 97, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 44, 32, 100,
-117, 105, 32, 110, 117, 108, 108, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 118, 101,
-104, 105, 99, 117, 108, 97, 32, 111, 100, 105, 111, 32, 97, 110, 116, 101, 32, 97, 116, 32, 115, 101, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 117, 108, 108, 97, 109,
-99, 111, 114, 112, 101, 114, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 112, 115, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105,
-115, 117, 115, 32, 110, 105, 98, 104, 44, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 116, 101, 109,
-112, 117, 115, 32, 101, 103, 101, 116, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 110, 101, 113, 117, 101, 46, 32, 83,
-101, 100, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 32, 117, 116, 32, 116, 111, 114, 116, 111, 114, 32, 102, 97, 99, 105, 108, 105, 115, 105,
-115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 97, 99, 32, 101, 108, 105, 116, 32, 113,
-117, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 98, 108, 97, 110, 100, 105, 116, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 101, 109,
-46, 32, 78, 97, 109, 32, 115, 101, 100, 32, 101, 114, 111, 115, 32, 118, 101, 108, 32, 108, 97, 99, 117, 115, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 80, 114, 111, 105, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 117, 110, 99, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 111, 114, 99, 105, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 115, 116, 97, 115, 32, 101, 110, 105, 109, 32,
-101, 117, 32, 111, 100, 105, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 32, 109, 101, 116, 117, 115, 46, 32, 80, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 44, 32, 115, 101, 109, 32, 118, 97, 114, 105, 117, 115, 32, 108, 117,
-99, 116, 117, 115, 32, 116, 101, 109, 112, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 109, 97, 103, 110, 97, 32, 99, 117, 114, 115, 117, 115,
-32, 110, 101, 113, 117, 101, 44, 32, 101, 116, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 100, 105, 97, 109, 32, 100, 105, 97, 109, 32, 113,
-117, 105, 115, 32, 112, 117, 114, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 100,
-111, 108, 111, 114, 46, 32, 78, 117, 108, 108, 97, 32, 105, 110, 32, 109, 97, 103, 110, 97, 46, 32, 67, 114, 97, 115, 32, 105, 100, 32, 100, 105,
-97, 109, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32,
-78, 117, 110, 99, 32, 112, 111, 114, 116, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 115, 97, 112, 105, 101, 110, 46, 32, 69, 116, 105, 97, 109,
-32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116,
-105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101,
-114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104,
-121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109,
-105, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32,
-100, 105, 97, 109, 32, 110, 111, 110, 32, 117, 114, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 108, 117, 99, 116, 117, 115, 32, 112, 104, 97, 114,
-101, 116, 114, 97, 32, 116, 101, 108, 108, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 97, 99, 32, 105, 112, 115, 117, 109, 32, 101, 103, 101, 116,
-32, 108, 105, 98, 101, 114, 111, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 67, 114, 97, 115, 32,
-105, 100, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115, 46, 32, 73, 110, 32, 100,
-111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 113, 117, 97, 109, 32, 105, 110, 32,
-109, 97, 115, 115, 97, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 114, 116, 97, 46, 32, 77, 111, 114, 98, 105, 32, 117, 116, 32, 100,
-111, 108, 111, 114, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 115, 116, 97, 115, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105,
-116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 111, 32,
-105, 110, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 101, 114, 97, 116, 32, 97, 32, 117, 114, 110,
-97, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 101, 109, 112, 101, 114, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 117,
-116, 32, 109, 101, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 108, 101, 105, 102, 101,
-110, 100, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 113, 117, 105, 115, 32, 117, 114, 110, 97, 46, 32, 67, 117, 114, 97, 98,
-105, 116, 117, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 117, 105, 46, 32, 78, 97, 109, 32,
-110, 101, 99, 32, 97, 110, 116, 101, 46, 32, 73, 110, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 109, 97, 116,
-116, 105, 115, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 117, 116, 32, 110, 101, 113, 117, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32,
-114, 105, 115, 117, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 85, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 101,
-99, 116, 117, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 117, 105, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78,
-117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-117, 114, 110, 97, 46, 32, 67, 114, 97, 115, 32, 118, 97, 114, 105, 117, 115, 32, 116, 111, 114, 116, 111, 114, 32, 105, 110, 32, 112, 101, 100, 101,
-46, 32, 83, 101, 100, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 108, 97, 99, 105, 110, 105,
-97, 32, 108, 105, 98, 101, 114, 111, 32, 110, 101, 99, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 108, 105, 113, 117, 97, 109,
-32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 110, 105, 115, 108, 46, 32, 78, 97, 109, 32, 97, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102,
-101, 108, 105, 115, 32, 116, 101, 109, 112, 111, 114, 32, 102, 101, 117, 103, 105, 97, 116, 46, 32, 78, 117, 110, 99, 32, 109, 101, 116, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 109, 101, 116, 117, 115, 32, 105, 110, 32, 115, 101,
-109, 112, 101, 114, 32, 108, 97, 111, 114, 101, 101, 116, 44, 32, 117, 114, 110, 97, 32, 105, 112, 115, 117, 109, 32, 112, 104, 97, 114, 101, 116, 114,
-97, 32, 108, 111, 114, 101, 109, 44, 32, 115, 101, 100, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 109, 97, 103, 110, 97, 32, 108, 111, 114,
-101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115, 105, 46, 32, 83, 101, 100, 32, 119, 105, 115, 105, 46, 32, 78, 117, 108, 108,
-97, 109, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 110, 105, 115, 108, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 109, 97, 116, 116, 105, 115, 32, 108, 101, 111, 32, 110, 101, 99, 32, 109, 97, 115, 115, 97, 46, 32, 65, 101, 110, 101,
-97, 110, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 67, 114, 97, 115, 32, 119, 105, 115, 105, 32, 101, 114, 97, 116, 44, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 110, 101, 99, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 97, 116, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 110, 105, 115, 108, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 110, 111, 110, 44, 32, 99, 117, 114, 115, 117, 115, 32, 110, 101, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 115, 101,
-100, 44, 32, 108, 97, 99, 117, 115, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97,
-46, 32, 67, 114, 97, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 110, 101, 113, 117, 101, 32, 97, 99, 32, 115, 117, 115, 99, 105, 112, 105,
-116, 32, 116, 101, 109, 112, 117, 115, 44, 32, 118, 101, 108, 105, 116, 32, 108, 111, 114, 101, 109, 32, 108, 117, 99, 116, 117, 115, 32, 101, 108, 105,
-116, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 114, 104, 111, 110, 99, 117, 115, 32, 119, 105, 115, 105, 32, 101, 115, 116, 32, 117, 116, 32, 115,
-101, 109, 46, 32, 80, 114, 111, 105, 110, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 110, 105, 109, 32, 105, 110, 32, 101, 114, 111, 115,
-32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 85, 116, 32, 108, 111, 114, 101, 109, 32, 110, 105,
-115, 108, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 116, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 101, 99, 44, 32,
-108, 97, 99, 105, 110, 105, 97, 32, 105, 110, 44, 32, 100, 111, 108, 111, 114, 46, 32, 68, 117, 105, 115, 32, 110, 101, 99, 32, 113, 117, 97, 109,
-46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 101, 108, 105, 116, 32, 102, 101, 108, 105, 115, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32,
-105, 100, 44, 32, 108, 117, 99, 116, 117, 115, 32, 113, 117, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 117, 116, 44, 32, 105, 112, 115,
-117, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 101, 103, 101, 116, 32, 97, 114, 99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 109,
-97, 115, 115, 97, 32, 102, 101, 108, 105, 115, 44, 32, 111, 114, 110, 97, 114, 101, 32, 110, 111, 110, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115,
-32, 105, 100, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 44, 32, 101, 108, 105, 116, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 109, 105, 32, 97, 99, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 102, 97, 99, 105, 108,
-105, 115, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 101, 110, 105, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 108, 101, 111, 44, 32,
-110, 111, 110, 32, 110, 111, 110, 117, 109, 109, 121, 32, 112, 101, 100, 101, 32, 100, 105, 97, 109, 32, 101, 103, 101, 116, 32, 110, 105, 98, 104, 46,
-32, 83, 101, 100, 32, 116, 101, 109, 112, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 117, 115,
-99, 105, 112, 105, 116, 32, 100, 117, 105, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116,
-46, 32, 85, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 78, 97, 109, 32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 110, 117, 108,
-108, 97, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 114, 117, 116, 114, 117, 109, 44, 32, 111, 114, 99, 105, 32, 101, 108, 105,
-116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97, 101, 32, 109, 111, 108, 108, 105, 115, 32, 111, 100, 105,
-111, 32, 111, 100, 105, 111, 32, 101, 116, 32, 112, 117, 114, 117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 46, 32, 83, 101, 100, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115,
-117, 109, 46, 32, 73, 110, 32, 117, 116, 32, 101, 115, 116, 46, 32, 69, 116, 105, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109,
-46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 111, 114, 116, 111, 114,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 108, 97, 99, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 111, 114, 99, 105, 46, 32, 83, 117,
-115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 108, 97, 99, 117, 115, 32, 110, 117, 108, 108, 97, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 97,
-44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 101, 114,
-111, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 117, 99, 116, 111, 114, 32, 103, 114, 97, 118, 105, 100, 97, 32, 110, 105, 115, 108, 46, 32, 67,
-114, 97, 115, 32, 97, 99, 32, 101, 115, 116, 32, 114, 117, 116, 114, 117, 109, 32, 97, 117, 103, 117, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-32, 111, 114, 110, 97, 114, 101, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 109, 97, 117, 114, 105, 115, 32, 110, 105, 98, 104, 44, 32,
-118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 105, 110, 44, 32, 114, 104, 111, 110, 99, 117, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44,
-32, 100, 97, 112, 105, 98, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 97, 99, 117, 115, 46, 32, 78, 97, 109, 32, 110, 117, 110, 99, 32, 109,
-97, 117, 114, 105, 115, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 97, 44,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 97, 109, 32, 97, 99, 99, 117, 109,
-115, 97, 110, 32, 109, 111, 108, 108, 105, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 109, 97, 116, 116, 105, 115, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115, 46, 32,
-78, 117, 108, 108, 97, 109, 32, 97, 99, 32, 115, 97, 112, 105, 101, 110, 32, 105, 100, 32, 109, 97, 115, 115, 97, 32, 108, 111, 98, 111, 114, 116,
-105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 108, 101, 109, 101, 110,
-116, 117, 109, 46, 32, 80, 114, 111, 105, 110, 32, 117, 116, 32, 112, 117, 114, 117, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 32, 113, 117, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 109, 111, 108, 108, 105,
-115, 46, 32, 78, 117, 108, 108, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 46, 32, 80, 114, 111, 105, 110, 32, 97, 32, 119, 105, 115, 105,
-32, 117, 116, 32, 116, 101, 108, 108, 117, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 65, 108,
-105, 113, 117, 97, 109, 32, 110, 117, 108, 108, 97, 32, 108, 111, 114, 101, 109, 44, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 97, 99, 44, 32,
-109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 101, 116, 44, 32, 109, 101, 116,
-117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 103, 101, 115, 116, 97, 115, 32, 110, 105, 98, 104, 32, 101, 116, 32, 108, 105,
-103, 117, 108, 97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 100, 105, 97, 109, 32, 111, 100, 105, 111, 44, 32, 108, 97, 99, 105, 110, 105, 97,
-32, 113, 117, 105, 115, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 113, 117, 105, 115, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117,
-100, 105, 110, 32, 117, 116, 44, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-108, 111, 114, 101, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 101, 100, 32, 99, 117, 114, 115, 117, 115, 32, 116, 101, 108, 108, 117,
-115, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 116, 32, 110, 117, 108, 108, 97, 46, 32, 68,
-111, 110, 101, 99, 32, 112, 111, 114, 116, 97, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 105, 100, 32, 108, 101,
-99, 116, 117, 115, 32, 97, 116, 32, 109, 97, 115, 115, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 108, 97, 99, 117, 115,
-46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109,
-115, 116, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 116, 117, 114, 112, 105, 115, 46, 32, 83, 101, 100, 32, 115, 97, 103, 105, 116, 116, 105,
-115, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 100, 117, 105,
-46, 32, 78, 97, 109, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 116, 101, 109, 112, 111, 114, 32, 118, 105, 116, 97, 101, 44,
-32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 117, 116, 44, 32, 118, 101,
-108, 105, 116, 46, 32, 73, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 117, 103, 117, 101, 32, 97, 32, 97, 114, 99, 117, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 100, 105, 99, 116, 117, 109, 32, 117, 108,
-116, 114, 105, 99, 101, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 32, 112, 117, 114, 117, 115,
-32, 101, 116, 32, 111, 114, 99, 105, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 99, 105, 110, 105, 97, 46, 32, 85, 116, 32, 108, 101, 111, 46,
-32, 67, 114, 97, 115, 32, 115, 101, 109, 112, 101, 114, 44, 32, 108, 111, 114, 101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 116, 105, 110,
-99, 105, 100, 117, 110, 116, 32, 99, 111, 110, 103, 117, 101, 44, 32, 106, 117, 115, 116, 111, 32, 101, 114, 111, 115, 32, 118, 97, 114, 105, 117, 115,
-32, 112, 101, 100, 101, 44, 32, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 116, 117, 114, 112, 105, 115, 32, 108, 101, 99, 116, 117, 115,
-32, 110, 111, 110, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 113, 117, 97, 109, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 109, 97, 116, 116, 105, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 109, 97, 103, 110, 97,
-46, 32, 65, 101, 110, 101, 97, 110, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 100, 105, 97, 109, 32, 118, 101, 108, 32, 110, 105, 115, 108,
-32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115,
-101, 32, 118, 101, 108, 32, 100, 111, 108, 111, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 111, 110, 117, 109, 109, 121, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 97, 110, 116, 101, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 114, 111, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 99, 32, 100, 111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105, 115, 117, 115, 32, 109, 101, 116, 117, 115, 44, 32,
-97, 108, 105, 113, 117, 101, 116, 32, 101, 103, 101, 116, 44, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 116, 44, 32, 102, 101, 117, 103,
-105, 97, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 97, 116, 32, 110, 117, 110, 99, 32, 105, 100, 32, 97, 110, 116,
-101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 68, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 32, 109, 97, 116, 116, 105, 115, 32, 97, 110, 116, 101, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 101, 113, 117,
-101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 105, 100, 44, 32, 99, 111, 110, 103, 117, 101, 32, 105, 110, 116,
-101, 114, 100, 117, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 117, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 118,
-111, 108, 117, 116, 112, 97, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99,
-117, 109, 115, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 100, 105, 97, 109, 46, 32, 69, 116, 105, 97, 109, 32, 118, 101, 108, 32, 100, 117, 105,
-32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 116, 101, 109, 112, 111, 114, 32, 118, 97, 114, 105, 117, 115, 46, 32, 67, 114, 97, 115, 32, 100,
-105, 99, 116, 117, 109, 32, 109, 97, 115, 115, 97, 32, 115, 101, 100, 32, 101, 110, 105, 109, 46, 32, 67, 114, 97, 115, 32, 117, 114, 110, 97, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 97, 99, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101,
-114, 32, 105, 110, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 101, 108, 44, 32, 97, 114, 99, 117, 46, 32, 77, 111, 114, 98, 105, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 108, 117, 99, 116, 117, 115, 32, 97, 117, 103, 117, 101, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 100, 117, 105,
-32, 100, 117, 105, 44, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 105, 110, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 101, 117,
-44, 32, 108, 117, 99, 116, 117, 115, 32, 101, 117, 44, 32, 110, 117, 108, 108, 97, 46, 32, 67, 114, 97, 115, 32, 118, 101, 108, 105, 116, 32, 112,
-101, 100, 101, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 102, 101, 117, 103, 105,
-97, 116, 32, 105, 110, 44, 32, 97, 117, 99, 116, 111, 114, 32, 118, 105, 116, 97, 101, 44, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 100, 105, 99, 116, 117, 109, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 109, 97, 117, 114, 105, 115, 46, 32,
-73, 110, 32, 97, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 108, 105, 103, 117, 108, 97, 46, 32, 73, 110, 32, 113,
-117, 97, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 116, 97, 101, 32, 117, 114, 110, 97, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 115, 101, 109, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109,
-32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 78, 97, 109, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 109, 101, 116, 117, 115, 46, 32, 85, 116, 32, 99, 111, 110, 103, 117, 101,
-46, 32, 68, 111, 110, 101, 99, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 97, 99,
-44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 99, 44, 32, 109, 111, 108, 108, 105, 115, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 111, 108, 117, 116,
-112, 97, 116, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 112, 101, 100, 101, 32, 111, 100, 105, 111,
-44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 110, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 109, 97, 108, 101, 115, 117, 97,
-100, 97, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 44, 32, 110, 117, 108, 108, 97, 46, 32, 78, 117, 108, 108,
-97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 101, 100, 101, 32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 46, 32, 80, 114, 111, 105, 110,
-32, 118, 101, 108, 105, 116, 32, 101, 108, 105, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 101,
-108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 118, 97, 114, 105, 117, 115, 32, 118, 105, 116, 97, 101, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 114, 117, 116, 114, 117, 109, 32, 105, 112, 115, 117, 109, 32, 101, 117, 32, 109, 105, 46, 32, 65,
-108, 105, 113, 117, 97, 109, 32, 101, 116, 32, 115, 101, 109, 46, 32, 73, 110, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 114, 104, 111,
-110, 99, 117, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78, 97, 109, 32, 118, 105, 118, 101, 114, 114, 97, 32, 115, 99, 101, 108, 101, 114, 105, 115,
-113, 117, 101, 32, 97, 114, 99, 117, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 115, 101, 109, 46, 32, 83, 101, 100, 32, 116, 105, 110, 99, 105,
-100, 117, 110, 116, 32, 110, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 109, 97, 115, 115, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97,
-117, 99, 105, 98, 117, 115, 32, 116, 101, 109, 112, 117, 115, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 108, 105, 113, 117, 101, 116, 32, 105, 97, 99,
-117, 108, 105, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 111, 100, 105, 111, 32,
-118, 105, 116, 97, 101, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 44, 32, 116, 101, 108, 108, 117, 115,
-32, 108, 105, 98, 101, 114, 111, 32, 99, 111, 109, 109, 111, 100, 111, 32, 105, 112, 115, 117, 109, 44, 32, 117, 116, 32, 115, 111, 108, 108, 105, 99,
-105, 116, 117, 100, 105, 110, 32, 110, 105, 115, 108, 32, 110, 105, 115, 108, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108,
-97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 110, 105,
-109, 32, 117, 116, 32, 106, 117, 115, 116, 111, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101, 108, 105,
-116, 32, 101, 103, 101, 116, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 111, 114, 99, 105, 32, 113,
-117, 97, 109, 32, 97, 117, 99, 116, 111, 114, 32, 110, 101, 113, 117, 101, 44, 32, 115, 101, 100, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32,
-100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 32, 118, 101, 108, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 111, 114, 99, 105, 32, 108,
-101, 111, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 118, 101, 108, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 111, 110, 44, 32, 115,
-101, 109, 112, 101, 114, 32, 101, 117, 44, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44,
-32, 108, 105, 98, 101, 114, 111, 32, 97, 99, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 99, 111, 109, 109, 111, 100, 111, 44,
-32, 101, 114, 111, 115, 32, 115, 97, 112, 105, 101, 110, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 105, 115, 108, 44, 32, 101, 117, 32, 101, 108,
-101, 105, 102, 101, 110, 100, 32, 110, 105, 98, 104, 32, 110, 105, 98, 104, 32, 118, 101, 108, 32, 108, 101, 99, 116, 117, 115, 46, 32, 86, 105, 118,
-97, 109, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 111, 100, 105, 111, 32, 100, 111, 108, 111,
-114, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 110, 111, 110, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 105, 100, 44, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 101, 103, 101, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 110, 99, 32, 109, 97, 117, 114, 105, 115, 32, 109, 97, 103,
-110, 97, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 100, 44, 32, 102, 101,
-114, 109, 101, 110, 116, 117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 44, 32, 109, 105, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 117, 115, 99,
-105, 112, 105, 116, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 110, 117, 110, 99, 46, 32, 80, 114, 111, 105, 110, 32, 113, 117, 105, 115, 32, 108,
-101, 99, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 109, 109, 111, 100, 111, 46,
-32, 78, 117, 110, 99, 32, 101, 103, 101, 116, 32, 100, 105, 97, 109, 32, 97, 99, 32, 101, 108, 105, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 117, 99, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 111, 100, 105, 111,
-32, 115, 101, 100, 32, 108, 97, 99, 105, 110, 105, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 44, 32, 106, 117, 115, 116, 111, 32, 109, 105,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 112, 117, 114, 117, 115, 44, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 108, 105, 98, 101, 114, 111, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 97, 99, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101,
-32, 103, 114, 97, 118, 105, 100, 97, 46, 32, 80, 114, 111, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 101, 114, 111, 115, 44, 32, 117, 108, 108,
-97, 109, 99, 111, 114, 112, 101, 114, 32, 105, 100, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 113, 117, 105, 115, 44, 32, 99, 111, 110, 100,
-105, 109, 101, 110, 116, 117, 109, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 115, 97, 112, 105, 101, 110, 46, 32, 83, 101, 100, 32, 101,
-116, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 116, 32, 108, 111, 114, 101, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 116, 101, 109, 112, 117,
-115, 46, 32, 68, 117, 105, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115,
-46, 32, 78, 97, 109, 32, 105, 100, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110,
-32, 111, 114, 99, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 101, 116, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97,
-32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 101, 108, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 111, 105,
-110, 32, 101, 103, 101, 116, 32, 101, 114, 97, 116, 46, 32, 68, 111, 110, 101, 99, 32, 110, 105, 115, 108, 46, 32, 77, 97, 101, 99, 101, 110, 97,
-115, 32, 97, 117, 99, 116, 111, 114, 32, 118, 101, 108, 105, 116, 32, 117, 116, 32, 112, 101, 100, 101, 46, 32, 78, 117, 110, 99, 32, 118, 105, 116,
-97, 101, 32, 108, 101, 99, 116, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 104,
-101, 110, 100, 114, 101, 114, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 44, 32, 101, 114, 97, 116, 32, 117,
-108, 116, 114, 105, 99, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 112, 117, 114, 117, 115, 32,
-108, 97, 99, 117, 115, 32, 100, 105, 99, 116, 117, 109, 32, 101, 114, 111, 115, 44, 32, 97, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 32, 101, 110, 105, 109, 32, 100, 117, 105, 32, 110, 101, 99, 32, 109, 97, 103, 110, 97, 46, 32, 77, 111, 114, 98, 105, 32, 100, 105, 97, 109,
-46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 115, 101, 100, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 110,
-101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 105, 110, 32, 97, 114, 99, 117, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 115, 111, 108, 108,
-105, 99, 105, 116, 117, 100, 105, 110, 46, 32, 73, 110, 32, 114, 117, 116, 114, 117, 109, 32, 110, 105, 115, 108, 32, 97, 116, 32, 97, 114, 99, 117,
-46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115,
-105, 109, 46, 32, 69, 116, 105, 97, 109, 32, 101, 115, 116, 32, 109, 97, 117, 114, 105, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 115,
-101, 100, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 101, 116, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 110,
-101, 113, 117, 101, 46, 32, 85, 116, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 105, 100, 32, 110, 105, 98, 104, 32, 108, 117, 99, 116, 117,
-115, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 97, 114, 105, 117, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 114, 105, 115, 117, 115, 46, 32, 85, 116, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 108, 105, 113, 117, 101, 116, 32, 114, 105,
-115, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 117, 99, 116, 117, 115, 32, 110, 101, 113, 117, 101, 32, 115, 105, 116,
-32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 110, 105, 98, 104, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 100, 97, 112, 105, 98, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 114, 111,
-115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 97, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 44, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116,
-117, 109, 32, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101,
-114, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 109, 105, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 105, 115, 108, 46, 32, 78,
-117, 108, 108, 97, 32, 101, 117, 32, 106, 117, 115, 116, 111, 32, 113, 117, 105, 115, 32, 100, 117, 105, 32, 112, 114, 101, 116, 105, 117, 109, 32, 114,
-104, 111, 110, 99, 117, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111,
-32, 109, 105, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 100, 111, 108, 111, 114, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 105, 118, 101,
-114, 114, 97, 32, 97, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 117, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 108, 101, 99,
-116, 117, 115, 32, 101, 116, 32, 109, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 97, 103, 105, 116, 116, 105, 115, 46, 32, 83, 101, 100, 32,
-97, 114, 99, 117, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99,
-32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 112, 117, 114, 117, 115, 32, 110, 111, 110, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-85, 116, 32, 108, 101, 111, 32, 119, 105, 115, 105, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44, 32, 103, 114, 97, 118, 105, 100, 97, 32, 97, 99, 44, 32, 108, 105, 98, 101, 114, 111, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 100, 97, 112, 105, 98, 117, 115, 32, 100, 105, 97, 109, 46, 32,
-73, 110, 116, 101, 103, 101, 114, 32, 113, 117, 105, 115, 32, 108, 97, 99, 117, 115, 32, 100, 97, 112, 105, 98, 117, 115, 32, 111, 100, 105, 111, 32,
-112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 112, 101, 100, 101, 32,
-113, 117, 97, 109, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 117, 116, 44, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 101, 116, 44, 32,
-116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32,
-101, 114, 111, 115, 32, 101, 110, 105, 109, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115, 101, 100, 44, 32, 97, 108, 105, 113, 117, 97,
-109, 32, 97, 99, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 97, 99, 44, 32, 101, 114, 97, 116, 46, 32, 85, 116, 32, 100, 105, 103, 110, 105,
-115, 115, 105, 109, 44, 32, 108, 97, 99, 117, 115, 32, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 97, 99, 117, 108, 105, 115, 44, 32,
-101, 110, 105, 109, 32, 111, 114, 99, 105, 32, 112, 111, 115, 117, 101, 114, 101, 32, 110, 117, 110, 99, 44, 32, 110, 101, 99, 32, 117, 108, 116, 114,
-105, 99, 105, 101, 115, 32, 108, 101, 99, 116, 117, 115, 32, 114, 105, 115, 117, 115, 32, 105, 110, 32, 111, 100, 105, 111, 46, 32, 69, 116, 105, 97,
-109, 32, 101, 116, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 100, 117, 105, 32, 99, 111, 109, 109, 111, 100, 111, 32, 118, 101, 104, 105, 99, 117,
-108, 97, 46, 32, 78, 117, 110, 99, 32, 98, 108, 97, 110, 100, 105, 116, 32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 105, 115, 32, 100, 117, 105,
-46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 105, 115, 108, 46, 32, 83, 101, 100, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 98, 108,
-97, 110, 100, 105, 116, 32, 108, 105, 103, 117, 108, 97, 46, 32, 70, 117, 115, 99, 101, 32, 118, 105, 118, 101, 114, 114, 97, 32, 105, 109, 112, 101,
-114, 100, 105, 101, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105,
-115, 32, 101, 115, 116, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 113, 117, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 111, 114, 99, 105,
-32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 110, 117, 110, 99, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103, 101, 116, 32, 108, 101, 111, 46, 32, 77, 111, 114, 98, 105, 32,
-118, 101, 108, 32, 117, 114, 110, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 83, 101, 100, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 108, 105, 98, 101, 114,
-111, 32, 101, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 99, 111, 110, 103, 117, 101, 44, 32, 119, 105, 115, 105, 32, 108,
-101, 99, 116, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 100, 111, 108, 111, 114, 44, 32, 101, 103, 101, 116, 32, 109, 111, 108, 101, 115, 116,
-105, 101, 32, 109, 97, 103, 110, 97, 32, 111, 114, 99, 105, 32, 118, 101, 108, 32, 116, 101, 108, 108, 117, 115, 46, 32, 83, 101, 100, 32, 116, 101,
-109, 112, 111, 114, 32, 97, 110, 116, 101, 32, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 101, 108, 105, 116, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 109,
-97, 115, 115, 97, 46, 32, 83, 101, 100, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 68, 117, 105, 115, 32, 110, 117, 108, 108, 97, 46, 32, 78,
-97, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 46, 32, 78, 97, 109, 32, 116, 111, 114, 116, 111, 114, 32, 108, 111, 114, 101, 109, 44, 32, 117,
-108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 105, 116, 97, 101, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 112, 111,
-115, 117, 101, 114, 101, 32, 101, 117, 44, 32, 106, 117, 115, 116, 111, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 97, 114, 99, 117, 32, 118, 105, 116, 97, 101, 32, 116, 117, 114, 112, 105, 115, 46, 32, 68, 111, 110, 101, 99, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 108, 105, 98, 101, 114, 111, 46, 32, 85, 116, 32, 115, 101, 100, 32, 116, 101,
-108, 108, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 110, 117, 110, 99, 32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 100,
-97, 112, 105, 98, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111,
-116, 101, 110, 116, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 108, 105, 98, 101, 114, 111, 32,
-101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 77, 97, 101, 99, 101,
-110, 97, 115, 32, 110, 111, 110, 32, 115, 101, 109, 32, 110, 111, 110, 32, 113, 117, 97, 109, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98,
-108, 97, 110, 100, 105, 116, 46, 32, 68, 117, 105, 115, 32, 114, 105, 115, 117, 115, 32, 116, 101, 108, 108, 117, 115, 44, 32, 114, 117, 116, 114, 117,
-109, 32, 118, 105, 116, 97, 101, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100,
-97, 32, 110, 101, 99, 44, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 110, 99, 32, 113, 117, 97, 109, 32, 100, 111, 108, 111, 114, 44, 32, 108,
-117, 99, 116, 117, 115, 32, 101, 103, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 114, 104, 111, 110, 99, 117,
-115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 68, 117, 105, 115, 32, 112, 101, 100, 101, 32, 108, 101, 99, 116, 117, 115, 44, 32,
-109, 97, 116, 116, 105, 115, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 44, 32, 116, 101, 109, 112, 111, 114, 32, 117, 116, 44, 32, 112, 111,
-114, 116, 97, 32, 97, 116, 44, 32, 109, 105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 114, 105, 115, 117, 115, 32, 110,
-117, 108, 108, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 115, 101, 100, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 100, 44, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 118, 105, 116, 97, 101, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 77, 111, 114, 98, 105, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 112, 101, 100, 101, 32, 117, 116, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 110, 99, 32, 114, 105, 115, 117, 115, 32,
-109, 97, 117, 114, 105, 115, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 101, 116, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 101,
-117, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 73, 110, 32, 102, 97, 117, 99, 105, 98,
-117, 115, 32, 102, 101, 108, 105, 115, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 78, 117, 108, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116,
-32, 101, 108, 105, 116, 46, 32, 78, 117, 108, 108, 97, 32, 101, 114, 97, 116, 32, 115, 97, 112, 105, 101, 110, 44, 32, 115, 97, 103, 105, 116, 116,
-105, 115, 32, 101, 103, 101, 116, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 101, 103, 101, 116, 44, 32, 118, 105, 118, 101, 114, 114, 97,
-32, 101, 117, 44, 32, 102, 101, 108, 105, 115, 46, 32, 78, 97, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 116, 117, 114, 112, 105, 115, 32, 118, 101, 108, 32, 115, 101, 109, 32, 108,
-97, 99, 105, 110, 105, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 111, 114, 110, 97, 114,
-101, 32, 105, 112, 115, 117, 109, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 46, 32, 68, 117, 105, 115, 32, 102, 97, 99, 105, 108, 105, 115,
-105, 115, 32, 110, 101, 113, 117, 101, 32, 113, 117, 105, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 116, 32, 101, 114,
-97, 116, 32, 101, 116, 32, 111, 114, 99, 105, 32, 108, 97, 99, 105, 110, 105, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46,
-32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 68, 117, 105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 105,
-112, 115, 117, 109, 32, 97, 99, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 97, 99, 99, 117,
-109, 115, 97, 110, 32, 97, 110, 116, 101, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 108, 101, 111,
-32, 117, 116, 32, 111, 114, 110, 97, 114, 101, 32, 97, 108, 105, 113, 117, 97, 109, 44, 32, 110, 117, 110, 99, 32, 101, 114, 97, 116, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 97, 114, 99, 117, 44, 32, 117, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 109, 105, 32, 97,
-117, 103, 117, 101, 32, 101, 116, 32, 110, 117, 108, 108, 97, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97,
-108, 105, 113, 117, 101, 116, 32, 119, 105, 115, 105, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 100, 117, 105, 46, 32, 69, 116,
-105, 97, 109, 32, 119, 105, 115, 105, 32, 108, 101, 111, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 105, 116, 97, 101, 44, 32, 118, 117, 108,
-112, 117, 116, 97, 116, 101, 32, 97, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 113, 117, 97, 109, 46, 32, 81, 117,
-105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 105, 110, 116, 101, 114, 100, 117,
-109, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 101, 114, 97, 116, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 101, 100, 44,
-32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118, 101, 108, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 102, 114, 105, 110, 103, 105, 108,
-108, 97, 44, 32, 97, 117, 103, 117, 101, 46, 32, 78, 117, 108, 108, 97, 32, 118, 101, 108, 32, 117, 114, 110, 97, 46, 32, 73, 110, 32, 108, 105,
-98, 101, 114, 111, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 101, 100, 44, 32, 109, 97, 116, 116, 105, 115, 32, 116, 101, 109,
-112, 117, 115, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 115, 101, 100, 44, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 113, 117, 97, 109, 32, 119, 105, 115, 105, 44, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 113, 117, 105, 115, 44,
-32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 97, 116, 44, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 32, 101, 103, 101, 116, 44, 32, 111, 100,
-105, 111, 46, 32, 78, 117, 108, 108, 97, 109, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32, 112, 117, 114, 117, 115, 32, 113, 117, 105, 115,
-32, 97, 108, 105, 113, 117, 97, 109, 32, 99, 117, 114, 115, 117, 115, 44, 32, 116, 117, 114, 112, 105, 115, 32, 111, 100, 105, 111, 32, 101, 103, 101,
-115, 116, 97, 115, 32, 106, 117, 115, 116, 111, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 32, 116, 117, 114,
-112, 105, 115, 32, 119, 105, 115, 105, 32, 118, 101, 108, 32, 116, 111, 114, 116, 111, 114, 46, 32, 78, 117, 110, 99, 32, 117, 108, 116, 114, 105, 99,
-105, 101, 115, 32, 112, 111, 114, 116, 97, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109,
-32, 101, 114, 97, 116, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 118, 101, 108, 32, 109, 97, 103, 110, 97, 32, 110, 101, 99, 32,
-109, 105, 32, 102, 101, 117, 103, 105, 97, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 85, 116, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110,
-32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101,
-115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 109, 97, 103, 110, 97, 32, 105, 110, 32, 100, 105, 97, 109, 32, 112, 111, 114, 116, 97, 32, 110, 111, 110, 117, 109, 109, 121, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 117, 116, 32, 115, 101, 109, 32, 105, 110, 32, 116, 117, 114, 112, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116,
-117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 116, 32, 111, 114, 99, 105, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105,
-115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101,
-115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 86,
-101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 114, 117, 116, 114, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108, 97,
-109, 32, 118, 105, 116, 97, 101, 32, 112, 101, 100, 101, 46, 32, 68, 111, 110, 101, 99, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32,
-110, 105, 98, 104, 32, 101, 116, 32, 111, 100, 105, 111, 46, 32, 83, 101, 100, 32, 101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 67, 108, 97, 115,
-115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111,
-114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32,
-112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 78, 97, 109, 32, 116, 101, 109, 112,
-117, 115, 46, 32, 83, 101, 100, 32, 97, 99, 32, 119, 105, 115, 105, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115,
-101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 119, 105, 115, 105, 46,
-32, 85, 116, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 73, 110, 116, 101, 103, 101, 114, 32, 109, 101, 116, 117, 115, 46, 32, 73, 110, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 117, 105, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 117, 114, 110,
-97, 46, 32, 78, 97, 109, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 117, 114,
-110, 97, 46, 32, 78, 117, 110, 99, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 101, 114, 97,
-116, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 44, 32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 99, 111, 109, 109, 111, 100,
-111, 32, 110, 111, 110, 117, 109, 109, 121, 44, 32, 108, 105, 103, 117, 108, 97, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 110, 105, 98, 104, 44, 32, 101, 117, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 110, 116, 101, 32, 110, 101, 113, 117, 101, 32, 115,
-101, 100, 32, 115, 101, 109, 46, 32, 69, 116, 105, 97, 109, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 106, 117, 115, 116, 111, 32,
-101, 103, 101, 116, 32, 119, 105, 115, 105, 46, 32, 78, 117, 110, 99, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 46, 32, 80, 114, 111, 105, 110,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109, 32, 110, 111, 110, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 114, 111, 105, 110,
-32, 117, 116, 32, 116, 117, 114, 112, 105, 115, 32, 113, 117, 105, 115, 32, 97, 117, 103, 117, 101, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113,
-117, 101, 32, 100, 105, 99, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 65, 108, 105, 113, 117,
-97, 109, 32, 117, 114, 110, 97, 32, 108, 97, 99, 117, 115, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 115, 101, 100, 44, 32, 118, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 101, 116, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 117, 99, 116, 111, 114, 32, 101, 114, 97, 116, 32, 110, 101, 99, 32, 108,
-111, 114, 101, 109, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 117, 114, 110, 97, 32, 119, 105, 115, 105, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 117, 116, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 105, 100, 44, 32, 111, 100, 105, 111, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 99, 111, 110, 118, 97,
-108, 108, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 106, 117, 115, 116, 111, 46, 32, 68, 111, 110, 101, 99, 32, 118, 101,
-115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 115, 116, 32, 97, 99, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 105, 116,
-97, 101, 32, 101, 108, 105, 116, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 118, 97, 114, 105, 117, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116,
-101, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112,
-111, 116, 101, 110, 116, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 110, 111, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 109, 97, 103, 110, 97, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 105, 98, 101, 114, 111, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 108, 117, 99, 116, 117, 115, 32, 97, 99, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 110, 103, 117,
-101, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 118, 101, 108, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 65, 101, 110,
-101, 97, 110, 32, 97, 114, 99, 117, 32, 97, 117, 103, 117, 101, 44, 32, 108, 117, 99, 116, 117, 115, 32, 105, 100, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116, 117, 115, 46,
-32, 68, 111, 110, 101, 99, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 100, 111, 108, 111, 114,
-46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114,
-105, 115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32,
-80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 103, 117, 101, 32, 116, 117, 114, 112, 105, 115, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 97, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 118, 105,
-116, 97, 101, 44, 32, 110, 105, 98, 104, 46, 32, 69, 116, 105, 97, 109, 32, 111, 114, 99, 105, 32, 115, 97, 112, 105, 101, 110, 44, 32, 99, 111,
-110, 103, 117, 101, 32, 105, 110, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 118, 101, 108, 44, 32, 110, 105, 98, 104, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 117, 32, 108, 111, 114, 101, 109, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 108, 101, 111, 32, 101, 116, 32, 101, 108, 105, 116, 46, 32, 73, 110, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 77, 97, 117, 114, 105, 115,
-32, 118, 97, 114, 105, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 101, 100, 32, 108, 105, 98, 101, 114, 111, 46, 32, 67, 117, 114, 97,
-98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 101, 108, 105, 116, 32, 101, 117, 32, 112, 117, 114, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 101, 108, 105, 116, 32, 112, 101, 100, 101, 44, 32, 115, 101, 109, 112, 101, 114, 32, 115,
-105, 116, 32, 97, 109, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 118, 105, 116, 97, 101, 44, 32, 116, 105, 110, 99, 105, 100, 117,
-110, 116, 32, 118, 101, 108, 44, 32, 100, 117, 105, 46, 32, 78, 117, 108, 108, 97, 32, 110, 101, 113, 117, 101, 32, 97, 110, 116, 101, 44, 32, 115,
-97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 97, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 77, 111, 114, 98, 105, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115,
-105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 110, 111, 110, 32, 102, 101, 108, 105, 115, 32, 113, 117, 105, 115, 32, 97,
-114, 99, 117, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 65, 101, 110, 101, 97, 110, 32, 101, 110, 105, 109,
-32, 109, 101, 116, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 117, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 110, 111,
-110, 117, 109, 109, 121, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 117, 116, 44, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 101,
-108, 101, 105, 102, 101, 110, 100, 32, 110, 105, 115, 108, 32, 113, 117, 105, 115, 32, 100, 111, 108, 111, 114, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 110, 32, 101, 114, 97, 116, 32, 109, 111, 108, 101, 115, 116, 105,
-101, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 97, 112,
-105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 114, 105, 115, 117, 115, 32, 105, 100, 32, 110, 101,
-113, 117, 101, 32, 100, 105, 99, 116, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 83, 101, 100, 32, 101, 117, 32, 108, 105, 103, 117, 108, 97,
-32, 97, 116, 32, 102, 101, 108, 105, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 83, 101, 100, 32,
-105, 110, 116, 101, 114, 100, 117, 109, 44, 32, 117, 114, 110, 97, 32, 110, 111, 110, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 104, 101, 110, 100,
-114, 101, 114, 105, 116, 44, 32, 113, 117, 97, 109, 32, 109, 105, 32, 111, 114, 110, 97, 114, 101, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100,
-32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 116, 111, 114, 116, 111, 114, 32, 111, 114, 99, 105, 32, 110, 111, 110, 32, 118, 101, 108, 105, 116,
-46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 110, 101, 99, 32, 114, 105, 115, 117, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 116, 32, 110, 117,
-110, 99, 32, 118, 105, 116, 97, 101, 32, 116, 101, 108, 108, 117, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 118, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 68, 117, 105,
-115, 32, 108, 105, 103, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 113, 117, 105, 115, 44,
-32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 118, 105,
-116, 97, 101, 44, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 116, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115,
-99, 101, 32, 101, 103, 101, 116, 32, 113, 117, 97, 109, 46, 32, 85, 116, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 109, 101, 116, 117, 115, 32, 110, 111, 110, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 108, 108,
-97, 32, 116, 101, 109, 112, 117, 115, 32, 108, 101, 111, 32, 117, 116, 32, 109, 105, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 105,
-116, 97, 101, 32, 110, 105, 115, 108, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 69, 116, 105,
-97, 109, 32, 97, 32, 111, 114, 99, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109,
-32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32,
-101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97,
-101, 59, 32, 86, 105, 118, 97, 109, 117, 115, 32, 117, 114, 110, 97, 32, 113, 117, 97, 109, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32,
-97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 118, 101, 108, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 101, 103, 101, 116, 44, 32,
-110, 117, 108, 108, 97, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 108, 97, 99, 117, 115, 32, 109, 97, 103, 110, 97, 44, 32, 110, 111, 110,
-117, 109, 109, 121, 32, 101, 117, 44, 32, 105, 97, 99, 117, 108, 105, 115, 32, 115, 101, 100, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117,
-101, 114, 32, 113, 117, 105, 115, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 97, 32, 101, 114, 111, 115, 46, 32,
-65, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 117, 109, 109, 121, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 101, 113, 117, 101, 46,
-32, 78, 117, 108, 108, 97, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 111, 108, 101, 115, 116, 105, 101, 44, 32,
-111, 114, 99, 105, 32, 113, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 118, 111, 108, 117, 116, 112, 97, 116, 44, 32, 108, 97,
-99, 117, 115, 32, 109, 101, 116, 117, 115, 32, 108, 117, 99, 116, 117, 115, 32, 115, 97, 112, 105, 101, 110, 44, 32, 101, 116, 32, 102, 97, 99, 105,
-108, 105, 115, 105, 115, 32, 101, 114, 111, 115, 32, 110, 101, 113, 117, 101, 32, 105, 100, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99,
-32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 100, 111, 108, 111, 114, 32, 118, 101, 108, 32, 111, 114, 99, 105, 46, 32, 73, 110, 116,
-101, 103, 101, 114, 32, 119, 105, 115, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109,
-101, 116, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 110, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 105, 110, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 81, 117, 105, 115, 113,
-117, 101, 32, 109, 111, 108, 108, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77,
-97, 117, 114, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 117, 116, 44, 32, 117, 108, 116,
-114, 105, 99, 101, 115, 32, 115, 101, 100, 44, 32, 112, 111, 114, 116, 97, 32, 105, 110, 44, 32, 106, 117, 115, 116, 111, 46, 32, 83, 117, 115, 112,
-101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 108, 97, 99, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115,
-46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 68, 111, 110, 101, 99, 32, 109, 111, 108,
-101, 115, 116, 105, 101, 44, 32, 109, 97, 103, 110, 97, 32, 115, 101, 100, 32, 101, 117, 105, 115, 109, 111, 100, 32, 100, 105, 99, 116, 117, 109, 44,
-32, 109, 97, 103, 110, 97, 32, 109, 97, 103, 110, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97,
-101, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 108, 101, 111, 32, 108, 111, 114, 101, 109, 32, 97, 99, 32, 110, 101, 113, 117, 101, 46, 32, 67,
-114, 97, 115, 32, 109, 101, 116, 117, 115, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 99, 111,
-110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 103, 114, 97, 118, 105, 100, 97, 32, 115,
-111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 117, 114, 110, 97, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 44, 32, 109, 97, 115, 115, 97, 32, 113, 117, 105, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-44, 32, 101, 114, 111, 115, 32, 112, 117, 114, 117, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 117, 110, 99, 44, 32, 101, 103, 101,
-116, 32, 114, 104, 111, 110, 99, 117, 115, 32, 101, 110, 105, 109, 32, 108, 101, 99, 116, 117, 115, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111,
-114, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 113, 117, 97, 109, 32, 113, 117, 105, 115, 32, 101, 114, 97,
-116, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 109, 97, 116, 116, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32,
-105, 97, 99, 117, 108, 105, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 118, 101, 108, 105, 116, 46, 32, 69, 116, 105, 97, 109, 32, 116, 101, 108,
-108, 117, 115, 32, 101, 110, 105, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 110, 101, 99, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 97,
-44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 110, 111, 110, 44, 32, 118, 101, 108, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108,
-97, 99, 117, 115, 32, 118, 101, 108, 105, 116, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32,
-102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 105, 100, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 44, 32, 108, 101, 99, 116, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 101, 113, 117, 101, 32, 101, 116, 32, 100, 117, 105, 46, 32, 80, 104, 97, 115, 101,
-108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 111, 100, 105, 111, 46, 32, 80,
-104, 97, 115, 101, 108, 108, 117, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 97, 114, 99, 117, 32, 97, 116, 32, 101, 114, 97, 116, 46, 32, 86, 105, 118, 97, 109, 117,
-115, 32, 117, 116, 32, 101, 114, 111, 115, 32, 117, 116, 32, 108, 111, 114, 101, 109, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 105, 97, 99, 117,
-108, 105, 115, 46, 32, 80, 114, 111, 105, 110, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115, 117, 109, 32, 105, 100, 32, 110, 117, 110,
-99, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 101, 108, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105,
-115, 115, 101, 32, 110, 117, 108, 108, 97, 32, 105, 112, 115, 117, 109, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 101, 103, 101, 116, 44, 32, 109, 111, 108, 108, 105, 115, 32, 97, 116, 44, 32, 114, 105, 115, 117, 115, 46, 32,
-86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 105, 100, 32, 101, 115, 116, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 80, 114, 111, 105, 110, 32, 116, 101, 109, 112, 117, 115, 44, 32, 101, 114, 111, 115, 32,
-97, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 44, 32, 105, 112, 115, 117, 109, 32,
-97, 114, 99, 117, 32, 97, 108, 105, 113, 117, 97, 109, 32, 109, 105, 44, 32, 117, 116, 32, 102, 101, 117, 103, 105, 97, 116, 32, 108, 105, 98, 101,
-114, 111, 32, 111, 100, 105, 111, 32, 105, 110, 32, 110, 105, 115, 108, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 101, 116, 32, 109, 97, 115, 115,
-97, 32, 97, 32, 109, 97, 117, 114, 105, 115, 32, 108, 117, 99, 116, 117, 115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 85, 116, 32, 105, 100, 32,
-101, 114, 111, 115, 46, 32, 70, 117, 115, 99, 101, 32, 97, 110, 116, 101, 32, 101, 114, 111, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32,
-110, 111, 110, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 44, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 119, 105, 115, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 114, 117, 116, 114,
-117, 109, 44, 32, 100, 111, 108, 111, 114, 32, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101,
-114, 111, 115, 32, 97, 110, 116, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 109, 97, 115, 115, 97, 44, 32, 115, 101, 100, 32, 115, 111,
-108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 118, 101, 108, 105, 116, 32, 101, 116, 32, 109, 97, 115, 115, 97,
-46, 32, 73, 110, 32, 97, 117, 99, 116, 111, 114, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 46, 32, 69, 116, 105, 97, 109, 32, 114, 105, 115, 117, 115, 32, 108, 101, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 101, 116, 44, 32, 115, 111, 100, 97, 108, 101,
-115, 32, 101, 103, 101, 116, 44, 32, 110, 105, 115, 108, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112,
-115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116,
-117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67,
-117, 114, 97, 101, 59, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111,
-32, 97, 99, 32, 108, 97, 111, 114, 101, 101, 116, 32, 109, 111, 108, 108, 105, 115, 44, 32, 108, 105, 103, 117, 108, 97, 32, 108, 101, 111, 32, 112,
-111, 114, 116, 97, 32, 119, 105, 115, 105, 44, 32, 117, 116, 32, 101, 117, 105, 115, 109, 111, 100, 32, 102, 101, 108, 105, 115, 32, 108, 105, 103, 117,
-108, 97, 32, 105, 100, 32, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 117,
-108, 108, 97, 32, 101, 117, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 102, 97, 117, 99,
-105, 98, 117, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97, 110, 116, 101, 46, 32, 80,
-114, 97, 101, 115, 101, 110, 116, 32, 97, 116, 32, 110, 105, 98, 104, 46, 32, 77, 97, 117, 114, 105, 115, 32, 112, 111, 114, 116, 97, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 32, 119, 105, 115, 105, 46, 32, 85, 116, 32, 108, 97, 99, 105, 110, 105, 97, 32, 116, 111, 114, 116, 111, 114, 32,
-110, 101, 99, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 116, 32, 97, 117, 103, 117, 101, 46, 32, 73, 110,
-116, 101, 103, 101, 114, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101,
-115, 113, 117, 101, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 116, 111, 114, 116, 111, 114, 32, 115, 97, 112, 105, 101, 110, 32, 108, 111, 98, 111,
-114, 116, 105, 115, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 115, 97, 112, 105,
-101, 110, 32, 114, 105, 115, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 108, 105, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101,
-32, 115, 101, 100, 32, 116, 117, 114, 112, 105, 115, 32, 117, 116, 32, 100, 111, 108, 111, 114, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 108, 101, 111, 46, 32, 67, 114, 97, 115, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 97, 117, 99,
-116, 111, 114, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 114, 99, 117, 46,
-0};
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 58192f59219..56b8d284386 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -39,6 +39,8 @@ set(INC_SYS
set(SRC
drawgpencil.c
editaction_gpencil.c
+ gpencil_convert.c
+ gpencil_data.c
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 55224b87c59..b28c948db9f 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -40,6 +40,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_api.h"
+#include "BLF_translation.h"
+
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -57,12 +60,12 @@
#include "BIF_glutil.h"
#include "ED_gpencil.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
-#include "gpencil_intern.h"
-
/* ************************************************** */
/* GREASE PENCIL DRAWING */
@@ -118,7 +121,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* draw stroke curve */
if (G.debug & G_DEBUG) setlinestyle(2);
- glLineWidth(oldpressure * thickness);
+ glLineWidth(max_ff(oldpressure * thickness, 1.0));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
@@ -127,7 +130,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
*/
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
glEnd();
- glLineWidth(pt->pressure * thickness);
+ glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
@@ -412,7 +415,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
int i;
/* draw stroke curve */
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
@@ -422,7 +425,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
glEnd();
curpressure = pt->pressure;
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
@@ -440,6 +443,8 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
/* draw debug points of curve on top? */
/* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
if (debug) {
+ glPointSize((float)(thickness + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
glVertex3fv(&pt->x);
@@ -614,6 +619,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
bGPDspoint *pt;
int i;
+ glPointSize((float)(thickness_s + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
float co[2];
@@ -754,7 +761,7 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
{
bGPDstroke *gps;
- const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
int mask_orig = 0;
/* set up depth masks... */
@@ -873,7 +880,7 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* draw onion-skinning for a layer */
static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag, short debug, short lthick)
+ int UNUSED(cfra), int dflag, bool debug, short lthick)
{
const float alpha = gpl->color[3];
float color[4];
@@ -1044,6 +1051,51 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
}
}
+/* draw a short status message in the top-right corner */
+static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
+{
+ rcti rect;
+
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_RENDER_OGL)
+ return;
+
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
+
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
+ int xco, yco;
+
+ BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+
+ xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ yco = (rect.ymax - U.widget_unit);
+
+ /* text label */
+ UI_ThemeColor(TH_TEXT_HI);
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#else
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#endif
+
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+
+ glDisable(GL_BLEND);
+ }
+}
+
/* draw grease-pencil datablock */
static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
@@ -1059,7 +1111,13 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
*/
/* turn on alpha-blending */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ if (GLEW_VERSION_1_4) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
glEnable(GL_BLEND);
/* draw! */
@@ -1195,6 +1253,11 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
/* draw it! */
if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (onlyv2d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
@@ -1229,10 +1292,27 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
winy = ar->winy;
}
- /* draw it! */
- if (only3d) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+ /* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (only3d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
new file mode 100644
index 00000000000..2c8f86423a5
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -0,0 +1,1484 @@
+/*
+ * ***** 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) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operator for converting Grease Pencil data to geometry
+ */
+
+/** \file blender/editors/gpencil/gpencil_convert.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_tracking.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+#include "ED_clip.h"
+#include "ED_keyframing.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Grease Pencil to Data Operator */
+
+/* defines for possible modes */
+enum {
+ GP_STROKECONVERT_PATH = 1,
+ GP_STROKECONVERT_CURVE,
+ GP_STROKECONVERT_POLY,
+};
+
+/* Defines for possible timing modes */
+enum {
+ GP_STROKECONVERT_TIMING_NONE = 1,
+ GP_STROKECONVERT_TIMING_LINEAR = 2,
+ GP_STROKECONVERT_TIMING_FULL = 3,
+ GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
+};
+
+/* RNA enum define */
+static EnumPropertyItem prop_gpencil_convertmodes[] = {
+ {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
+ {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
+ {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
+ {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
+ "Use the original timing, but with custom gap lengths (in frames)"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ if (RNA_boolean_get(ptr, "use_timing_data")) {
+ return prop_gpencil_convert_timingmodes;
+ }
+ return prop_gpencil_convert_timingmodes_restricted;
+}
+
+/* --- */
+
+/* convert the coordinates from the given stroke point into 3d-coordinates
+ * - assumes that the active space is the 3D-View
+ */
+static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* directly use 3d-coordinates */
+ copy_v3_v3(p3d, &pt->x);
+ }
+ else {
+ const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+ float mvalf[2];
+
+ /* get screen coordinate */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = &ar->v2d;
+ UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
+ }
+ else {
+ if (subrect) {
+ mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ else {
+ mvalf[0] = (float)pt->x / 100.0f * ar->winx;
+ mvalf[1] = (float)pt->y / 100.0f * ar->winy;
+ }
+ }
+
+ ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
+ }
+}
+
+/* --- */
+
+/* temp struct for gp_stroke_path_animation() */
+typedef struct tGpTimingData {
+ /* Data set from operator settings */
+ int mode;
+ int frame_range; /* Number of frames evaluated for path animation */
+ int start_frame, end_frame;
+ bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
+ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
+ int seed;
+
+ /* Data set from points, used to compute final timing FCurve */
+ int num_points, cur_point;
+
+ /* Distances */
+ float *dists;
+ float tot_dist;
+
+ /* Times */
+ float *times; /* Note: Gap times will be negative! */
+ float tot_time, gap_tot_time;
+ double inittime;
+
+ /* Only used during creation of dists & times lists. */
+ float offset_time;
+} tGpTimingData;
+
+/* Init point buffers for timing data.
+ * Note this assumes we only grow those arrays!
+ */
+static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
+{
+ float *tmp;
+
+ BLI_assert(nbr > gtd->num_points);
+
+ /* distances */
+ tmp = gtd->dists;
+ gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ /* times */
+ tmp = gtd->times;
+ gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ gtd->num_points = nbr;
+}
+
+/* add stroke point to timing buffers */
+static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
+ const float delta_dist)
+{
+ float delta_time = 0.0f;
+ const int cur_point = gtd->cur_point;
+
+ if (!cur_point) {
+ /* Special case, first point, if time is not 0.0f we have to compensate! */
+ gtd->offset_time = -time;
+ gtd->times[cur_point] = 0.0f;
+ }
+ else if (time < 0.0f) {
+ /* This is a gap, negative value! */
+ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
+
+ gtd->gap_tot_time += delta_time;
+ }
+ else {
+ gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
+ }
+
+ gtd->tot_time += delta_time;
+ gtd->tot_dist += delta_dist;
+ gtd->dists[cur_point] = gtd->tot_dist;
+
+ gtd->cur_point++;
+}
+
+/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
+ * arbitrarily close points - this is esp. important with NoGaps mode!
+ */
+#define MIN_TIME_DELTA 0.02f
+
+/* Loop over next points to find the end of the stroke, and compute */
+static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
+ int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
+ float *next_delta_time)
+{
+ int j;
+
+ for (j = idx + 1; j < gtd->num_points; j++) {
+ if (gtd->times[j] < 0) {
+ gtd->times[j] = -gtd->times[j];
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* In this mode, gap time between this stroke and the next should be 0 currently...
+ * So we have to compute its final duration!
+ */
+ if (gtd->gap_randomness > 0.0f) {
+ /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
+ * and which sum to exactly tot_gaps_time...
+ */
+ int rem_gaps = nbr_gaps - (*nbr_done_gaps);
+ if (rem_gaps < 2) {
+ /* Last gap, just give remaining time! */
+ *next_delta_time = tot_gaps_time;
+ }
+ else {
+ float delta, min, max;
+
+ /* This code ensures that if the first gaps have been shorter than average gap_duration,
+ * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
+ */
+ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
+
+ /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
+ min = -gtd->gap_randomness - delta;
+ CLAMP(min, -gtd->gap_randomness, 0.0f);
+
+ /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
+ max = gtd->gap_randomness - delta;
+ CLAMP(max, 0.0f, gtd->gap_randomness);
+ *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
+ }
+ }
+ else {
+ *next_delta_time += gtd->gap_duration;
+ }
+ }
+ (*nbr_done_gaps)++;
+ break;
+ }
+ }
+
+ return j - 1;
+}
+
+static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
+{
+ int i;
+ float delta_time = 0.0f;
+
+ for (i = 0; i < gtd->num_points; i++) {
+ if (gtd->times[i] < 0 && i) {
+ (*nbr_gaps)++;
+ gtd->times[i] = -gtd->times[i] - delta_time;
+ delta_time += gtd->times[i] - gtd->times[i - 1];
+ gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
+ }
+ else {
+ gtd->times[i] -= delta_time;
+ }
+ }
+ gtd->tot_time -= delta_time;
+
+ *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
+ gtd->tot_time += *tot_gaps_time;
+ if (G.debug & G_DEBUG) {
+ printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
+ }
+ if (gtd->gap_randomness > 0.0f) {
+ BLI_rng_srandom(rng, gtd->seed);
+ }
+}
+
+static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
+ Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
+ const int nbr_gaps, const float tot_gaps_time)
+{
+ /* Use actual recorded timing! */
+ const float time_start = (float)gtd->start_frame;
+
+ float last_valid_time = 0.0f;
+ int end_stroke_idx = -1, start_stroke_idx = 0;
+ float end_stroke_time = 0.0f;
+
+ /* CustomGaps specific */
+ float delta_time = 0.0f, next_delta_time = 0.0f;
+ int nbr_done_gaps = 0;
+
+ int i;
+ float cfra;
+
+ /* This is a bit tricky, as:
+ * - We can't add arbitrarily close points on FCurve (in time).
+ * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
+ */
+ for (i = 0; i < gtd->num_points; i++) {
+ /* If new stroke... */
+ if (i > end_stroke_idx) {
+ start_stroke_idx = i;
+ delta_time = next_delta_time;
+ /* find end of that new stroke */
+ end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
+ tot_gaps_time, delta_time, &next_delta_time);
+ /* This one should *never* be negative! */
+ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
+ }
+
+ /* Simple proportional stuff... */
+ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
+ cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
+
+ /* And now, the checks about timing... */
+ if (i == start_stroke_idx) {
+ /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
+ * that the end point of the stroke is far enough!
+ * In case it is not, we keep the end point...
+ * Note that with CustomGaps mode, this is here we set the actual gap timing!
+ */
+ if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
+ }
+ }
+ else if (i == end_stroke_idx) {
+ /* Always try to insert end point of a curve (should be safe enough, anyway...) */
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else {
+ /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
+ * and also far enough from (not yet added!) end_stroke keyframe!
+ */
+ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
+ i, end_stroke_idx);
+ }
+ }
+ }
+}
+
+static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
+{
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+ FCurve *fcu;
+ PointerRNA ptr;
+ PropertyRNA *prop = NULL;
+ int nbr_gaps = 0, i;
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
+ return;
+
+ /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
+ gtd->gap_duration = FRA2TIME(gtd->gap_duration);
+ gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
+
+ /* Enable path! */
+ cu->flag |= CU_PATH;
+ cu->pathlen = gtd->frame_range;
+
+ /* Get RNA pointer to read/write path time values */
+ RNA_id_pointer_create((ID *)cu, &ptr);
+ prop = RNA_struct_find_property(&ptr, "eval_time");
+
+ /* Ensure we have an F-Curve to add keyframes to */
+ act = verify_adt_action((ID *)cu, true);
+ fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ }
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
+ float cfra;
+
+ /* Linear extrapolation! */
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+
+ cu->ctime = 0.0f;
+ cfra = (float)gtd->start_frame;
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+
+ cu->ctime = cu->pathlen;
+ if (gtd->realtime) {
+ cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ cfra = (float)gtd->end_frame;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ }
+ else {
+ /* Use actual recorded timing! */
+ RNG *rng = BLI_rng_new(0);
+ float time_range;
+
+ /* CustomGaps specific */
+ float tot_gaps_time = 0.0f;
+
+ /* Pre-process gaps, in case we don't want to keep their original timing */
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
+ }
+
+ if (gtd->realtime) {
+ time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ time_range = (float)(gtd->end_frame - gtd->start_frame);
+ }
+
+ if (G.debug & G_DEBUG) {
+ printf("GP Stroke Path Conversion: Starting keying!\n");
+ }
+
+ gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
+ nbr_gaps, tot_gaps_time);
+
+ BLI_rng_free(rng);
+ }
+
+ /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
+ calchandles_fcurve(fcu);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ printf("\n\n");
+ }
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ /* send updates */
+ DAG_id_tag_update(&cu->id, 0);
+}
+
+#undef MIN_TIME_DELTA
+
+#define GAP_DFAC 0.01f
+#define WIDTH_CORR_FAC 0.1f
+#define BEZT_HANDLE_FAC 0.3f
+
+/* convert stroke to 3d path */
+
+/* helper */
+static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bp->vec, p);
+ bp->vec[3] = 1.0f;
+
+ /* set settings */
+ bp->f1 = SELECT;
+ bp->radius = width * rad_fac;
+ bp->weight = width;
+ CLAMP(bp->weight, 0.0f, 1.0f);
+ if (bp->weight < minmax_weights[0]) {
+ minmax_weights[0] = bp->weight;
+ }
+ else if (bp->weight > minmax_weights[1]) {
+ minmax_weights[1] = bp->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BPoint *bp, *prev_bp = NULL;
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ int i, old_nbp = 0;
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbp = nu->pntsu;
+
+ /* If stitch, the first point of this stroke is already present in current nu.
+ * Else, we have to add two additional points to make the zero-radius link between strokes.
+ */
+ BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->pntsv = 1;
+ nu->orderu = 2; /* point-to-point! */
+ nu->type = CU_NURBS;
+ nu->flagu = CU_NURB_ENDPOINT;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->knotsu = NULL;
+
+ nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ if (curnu && !stitch && old_nbp) {
+ float p1[3], p2[3], p[3], next_p[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ BLI_assert(gps->prev != NULL);
+
+ prev_bp = NULL;
+ if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bp = &nu->bp[old_nbp - 2];
+ }
+ bp = &nu->bp[old_nbp - 1];
+
+ /* First point */
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (prev_bp) {
+ interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp += 2;
+ }
+ else if (add_start_point) {
+ float p[3], next_p[3];
+ float dt = 0.0f;
+
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ bp = &nu->bp[old_nbp];
+ /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
+ * would not work (it would be *before* gtd->inittime, which is not supported currently).
+ */
+ gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp++;
+ }
+
+ if (old_nbp) {
+ prev_bp = &nu->bp[old_nbp - 1];
+ }
+
+ /* add points */
+ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
+ i < gps->totpoints;
+ i++, pt++, bp++)
+ {
+ float p[3];
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ /* get coordinates to add at */
+ gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+
+ gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
+ width, rad_fac, minmax_weights);
+
+ prev_bp = bp;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bp->vec);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+ /* Note bp has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* add nurb to curve */
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+}
+
+/* convert stroke to 3d bezier */
+
+/* helper */
+static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
+ const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bezt->vec[0], h1);
+ copy_v3_v3(bezt->vec[1], p);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* set settings */
+ bezt->h1 = bezt->h2 = HD_FREE;
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->radius = width * rad_fac;
+ bezt->weight = width;
+ CLAMP(bezt->weight, 0.0f, 1.0f);
+ if (bezt->weight < minmax_weights[0]) {
+ minmax_weights[0] = bezt->weight;
+ }
+ else if (bezt->weight > minmax_weights[1]) {
+ minmax_weights[1] = bezt->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BezTriple *bezt, *prev_bezt = NULL;
+ int i, tot, old_nbezt = 0;
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbezt = nu->pntsu;
+ /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
+ * so no need to add it.
+ * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
+ */
+ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->resolu = 12;
+ nu->resolv = 12;
+ nu->type = CU_BEZIER;
+ nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ tot = gps->totpoints;
+
+ /* get initial coordinates */
+ pt = gps->points;
+ if (tot) {
+ gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ if (tot > 1) {
+ gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ }
+ if (stitch && tot > 2) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ if (curnu && old_nbezt) {
+ BLI_assert(gps->prev != NULL);
+
+ /* Update last point's second handle */
+ if (stitch) {
+ bezt = &nu->bezt[old_nbezt - 1];
+ interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+ pt++;
+ }
+
+ /* Create "link points" */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ else {
+ float p1[3], p2[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ prev_bezt = NULL;
+ if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bezt = &nu->bezt[old_nbezt - 2];
+ }
+ bezt = &nu->bezt[old_nbezt - 1];
+
+ /* First point */
+ if (prev_bezt) {
+ interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (tot > 1) {
+ interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second handle of last point of previous stroke. */
+ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* First point */
+ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt += 2;
+ copy_v3_v3(p3d_prev, p2);
+ }
+ }
+ else if (add_start_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, p3d_cur);
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
+ bezt = &nu->bezt[old_nbezt];
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt++;
+ copy_v3_v3(p3d_prev, p);
+ }
+
+ if (old_nbezt) {
+ prev_bezt = &nu->bezt[old_nbezt - 1];
+ }
+
+ /* add points */
+ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ if (i || old_nbezt) {
+ interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
+ }
+
+ if (i < tot - 1) {
+ interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
+ }
+
+ gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
+ do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
+
+ /* shift coord vects */
+ copy_v3_v3(p3d_prev, p3d_cur);
+ copy_v3_v3(p3d_cur, p3d_next);
+
+ if (i + 2 < tot) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+
+ prev_bezt = bezt;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bezt->vec[1]);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+
+ /* Second handle of last point of this stroke. */
+ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
+ copy_v3_v3(prev_bezt->vec[2], h2);
+
+ /* The end point */
+ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
+ /* Note bezt has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* must calculate handles or else we crash */
+ BKE_nurb_handles_calc(nu);
+
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+}
+
+#undef GAP_DFAC
+#undef WIDTH_CORR_FAC
+#undef BEZT_HANDLE_FAC
+
+static void gp_stroke_finalize_curve_endpoints(Curve *cu)
+{
+ /* start */
+ Nurb *nu = cu->nurb.first;
+ int i = 0;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+
+ /* end */
+ nu = cu->nurb.last;
+ i = nu->pntsu - 1;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+}
+
+static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
+{
+ Nurb *nu;
+ const float delta = minmax_weights[0];
+ float fac;
+ int i;
+
+ /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
+ if (IS_EQF(delta, minmax_weights[1]))
+ fac = 1.0f;
+ else
+ fac = 1.0f / (minmax_weights[1] - delta);
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ bezt->weight = (bezt->weight - delta) * fac;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bp++) {
+ bp->weight = (bp->weight - delta) * fac;
+ }
+ }
+ }
+}
+
+static int gp_camera_view_subrect(bContext *C, rctf *subrect)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (v3d) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ Scene *scene = CTX_data_scene(C);
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
+static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
+ const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
+{
+ struct Main *bmain = CTX_data_main(C);
+ View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDstroke *gps, *prev_gps = NULL;
+ Object *ob;
+ Curve *cu;
+ Nurb *nu = NULL;
+ Base *base_orig = BASACT, *base_new = NULL;
+ float minmax_weights[2] = {1.0f, 0.0f};
+
+ /* camera framing */
+ rctf subrect, *subrect_ptr = NULL;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl, gpf))
+ return;
+
+ /* only convert if there are any strokes on this layer's frame to convert */
+ if (BLI_listbase_is_empty(&gpf->strokes))
+ return;
+
+ /* initialize camera framing */
+ if (gp_camera_view_subrect(C, &subrect)) {
+ subrect_ptr = &subrect;
+ }
+
+ /* init the curve object (remove rotation and get curve data from it)
+ * - must clear transforms set on object, as those skew our results
+ */
+ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
+ cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
+ base_new = BKE_scene_base_add(scene, ob);
+
+ cu->flag |= CU_3D;
+
+ gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
+
+ /* add points to curve */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ const bool add_start_point = (link_strokes && !(prev_gps));
+ const bool add_end_point = (link_strokes && !(gps->next));
+
+ /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
+ bool stitch = false;
+ if (prev_gps) {
+ bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
+ bGPDspoint *pt2 = &gps->points[0];
+
+ if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
+ stitch = true;
+ }
+ }
+
+ /* Decide whether we connect this stroke to previous one */
+ if (!(stitch || link_strokes)) {
+ nu = NULL;
+ }
+
+ switch (mode) {
+ case GP_STROKECONVERT_PATH:
+ gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ case GP_STROKECONVERT_CURVE:
+ case GP_STROKECONVERT_POLY: /* convert after */
+ gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ default:
+ BLI_assert(!"invalid mode");
+ break;
+ }
+ prev_gps = gps;
+ }
+
+ /* If link_strokes, be sure first and last points have a zero weight/size! */
+ if (link_strokes) {
+ gp_stroke_finalize_curve_endpoints(cu);
+ }
+
+ /* Update curve's weights, if needed */
+ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
+ gp_stroke_norm_curve_weights(cu, minmax_weights);
+ }
+
+ /* Create the path animation, if needed */
+ gp_stroke_path_animation(C, reports, cu, gtd);
+
+ if (mode == GP_STROKECONVERT_POLY) {
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ BKE_nurb_type_convert(nu, CU_POLY, false);
+ }
+ }
+
+ /* set the layer and select */
+ base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
+ base_new->flag = ob->flag = base_new->flag | SELECT;
+}
+
+/* --- */
+
+/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
+ * op may be NULL.
+ */
+static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = NULL;
+ bGPDstroke *gps = NULL;
+ bGPDspoint *pt;
+ double base_time, cur_time, prev_time = -1.0;
+ int i;
+ bool valid = true;
+
+ if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ return false;
+
+ do {
+ base_time = cur_time = gps->inittime;
+ if (cur_time <= prev_time) {
+ valid = false;
+ break;
+ }
+
+ prev_time = cur_time;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ cur_time = base_time + (double)pt->time;
+ /* First point of a stroke should have the same time as stroke's inittime,
+ * so it's the only case where equality is allowed!
+ */
+ if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
+ valid = false;
+ break;
+ }
+ prev_time = cur_time;
+ }
+
+ if (!valid) {
+ break;
+ }
+ } while ((gps = gps->next));
+
+ if (op) {
+ RNA_boolean_set(op->ptr, "use_timing_data", valid);
+ }
+ return valid;
+}
+
+/* Check end_frame is always > start frame! */
+static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
+{
+ int start_frame = RNA_int_get(ptr, "start_frame");
+ int end_frame = RNA_int_get(ptr, "end_frame");
+
+ if (end_frame <= start_frame) {
+ RNA_int_set(ptr, "end_frame", start_frame + 1);
+ }
+}
+
+static int gp_convert_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = NULL;
+ bGPDframe *gpf = NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
+ * and if we are not in edit mode!
+ */
+ return ((sa && sa->spacetype == SPACE_VIEW3D) &&
+ (gpl = gpencil_layer_getactive(gpd)) &&
+ (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpf->strokes.first) &&
+ (scene->obedit == NULL));
+}
+
+static int gp_convert_layer_exec(bContext *C, wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ Scene *scene = CTX_data_scene(C);
+ const int mode = RNA_enum_get(op->ptr, "type");
+ const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
+ const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
+ const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
+ bool valid_timing;
+ tGpTimingData gtd;
+
+ /* check if there's data to work with */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
+ BKE_report(op->reports, RPT_WARNING,
+ "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
+ }
+ valid_timing = RNA_property_boolean_get(op->ptr, prop);
+
+ gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
+ /* Check for illegal timing mode! */
+ if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
+ gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
+ RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
+ }
+ if (!link_strokes) {
+ gtd.mode = GP_STROKECONVERT_TIMING_NONE;
+ }
+
+ /* grab all relevant settings */
+ gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
+ gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
+ gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
+ gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
+ gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
+ gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
+ gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
+ gtd.seed = RNA_int_get(op->ptr, "seed");
+ gtd.num_points = gtd.cur_point = 0;
+ gtd.dists = gtd.times = NULL;
+ gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
+ gtd.inittime = 0.0;
+ gtd.offset_time = 0.0f;
+
+ /* perform conversion */
+ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
+
+ /* free temp memory */
+ if (gtd.dists) {
+ MEM_freeN(gtd.dists);
+ gtd.dists = NULL;
+ }
+ if (gtd.times) {
+ MEM_freeN(gtd.times);
+ gtd.times = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
+ int timing_mode = RNA_enum_get(ptr, "timing_mode");
+ bool realtime = RNA_boolean_get(ptr, "use_realtime");
+ float gap_duration = RNA_float_get(ptr, "gap_duration");
+ float gap_randomness = RNA_float_get(ptr, "gap_randomness");
+ const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
+
+ /* Always show those props */
+ if (STREQ(prop_id, "type") ||
+ STREQ(prop_id, "use_normalize_weights") ||
+ STREQ(prop_id, "radius_multiplier") ||
+ STREQ(prop_id, "use_link_strokes"))
+ {
+ return true;
+ }
+
+ /* Never show this prop */
+ if (STREQ(prop_id, "use_timing_data"))
+ return false;
+
+ if (link_strokes) {
+ /* Only show when link_stroke is true */
+ if (STREQ(prop_id, "timing_mode"))
+ return true;
+
+ if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
+ /* Only show when link_stroke is true and stroke timing is enabled */
+ if (STREQ(prop_id, "frame_range") ||
+ STREQ(prop_id, "start_frame"))
+ {
+ return true;
+ }
+
+ /* Only show if we have valid timing data! */
+ if (valid_timing && STREQ(prop_id, "use_realtime"))
+ return true;
+
+ /* Only show if realtime or valid_timing is false! */
+ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
+ return true;
+
+ if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* Only show for custom gaps! */
+ if (STREQ(prop_id, "gap_duration"))
+ return true;
+
+ /* Only show randomness for non-null custom gaps! */
+ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
+ return true;
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
+ return true;
+ }
+ }
+ }
+
+ /* Else, hidden! */
+ return false;
+}
+
+static void gp_convert_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
+}
+
+void GPENCIL_OT_convert(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Convert Grease Pencil";
+ ot->idname = "GPENCIL_OT_convert";
+ ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_convert_layer_exec;
+ ot->poll = gp_convert_poll;
+ ot->ui = gp_convert_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
+
+ RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
+ "Normalize weight (set from stroke width)");
+ RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
+ "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
+ "Whether to link strokes with zero-radius sections of curves");
+
+ prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
+ "Timing Mode", "How to use timing data stored in strokes");
+ RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
+
+ RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
+ "The duration of evaluation of the path control curve", 1, 1000);
+ RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
+ "The start frame of the path control curve", 1, 100000);
+ RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
+ "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
+ prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
+ "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
+ RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
+
+ RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
+ "Custom Gap mode: (Average) length of gaps, in frames "
+ "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
+ "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
+ "Custom Gap mode: Random generator seed", 0, 100);
+
+ /* Note: Internal use, this one will always be hidden by UI code... */
+ prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
+ "Whether the converted Grease Pencil layer has valid timing data (internal use)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
new file mode 100644
index 00000000000..fa76029bb2e
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -0,0 +1,447 @@
+/*
+ * ***** 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) 2008, Blender Foundation, Joshua Leung
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for dealing with GP datablocks and layers
+ */
+
+/** \file blender/editors/gpencil/gpencil_data.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 "BLF_translation.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+
+/* ************************************************ */
+/* Datablock Operators */
+
+/* ******************* Add New Data ************************ */
+
+/* add new datablock - wrapper around API */
+static int gp_data_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* decrement user count and add new datablock */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Add New";
+ ot->idname = "GPENCIL_OT_data_add";
+ ot->description = "Add new Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Unlink Data ************************ */
+
+/* poll callback for adding data/layers - special */
+static int gp_data_unlink_poll(bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if we have access to some active data, make sure there's a datablock before enabling this */
+ return (gpd_ptr && *gpd_ptr);
+}
+
+
+/* unlink datablock - wrapper around API */
+static int gp_data_unlink_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just unlink datablock now, decreasing its user count */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Unlink";
+ ot->idname = "GPENCIL_OT_data_unlink";
+ ot->description = "Unlink active Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_unlink_exec;
+ ot->poll = gp_data_unlink_poll;
+}
+
+
+/* ************************************************ */
+/* Layer Operators */
+
+/* ******************* Add New Layer ************************ */
+
+/* add new layer - wrapper around API */
+static int gp_layer_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+ /* add new layer now */
+ gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Layer";
+ ot->idname = "GPENCIL_OT_layer_add";
+ ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Layer ************************* */
+
+static int gp_layer_remove_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* make the layer before this the new active layer
+ * - use the one after if this is the first
+ * - if this is the only layer, this naturally becomes NULL
+ */
+ if (gpl->prev)
+ gpencil_layer_setactive(gpd, gpl->prev);
+ else
+ gpencil_layer_setactive(gpd, gpl->next);
+
+ /* delete the layer now... */
+ gpencil_layer_delete(gpd, gpl);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Layer";
+ ot->idname = "GPENCIL_OT_layer_remove";
+ ot->description = "Remove active Grease Pencil layer";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_remove_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Move Layer Up/Down ************************** */
+
+enum {
+ GP_LAYER_MOVE_UP = -1,
+ GP_LAYER_MOVE_DOWN = 1
+};
+
+static int gp_layer_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* up or down? */
+ if (direction == GP_LAYER_MOVE_UP) {
+ /* up */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
+ }
+ else {
+ /* down */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer";
+ ot->idname = "GPENCIL_OT_layer_move";
+ ot->description = "Move the active Grease Pencil layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_layer_move_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+
+/* ********************* Duplicate Layer ************************** */
+
+static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *new_layer;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* make copy of layer, and add it immediately after the existing layer */
+ new_layer = gpencil_layer_duplicate(gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
+
+ /* ensure new layer has a unique name, and is now the active layer */
+ BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
+ gpencil_layer_setactive(gpd, new_layer);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Layer";
+ ot->idname = "GPENCIL_OT_layer_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil layer";
+
+ /* callbacks */
+ ot->exec = gp_layer_copy_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************** Hide Layers ******************************** */
+
+static int gp_hide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, layer))
+ return OPERATOR_CANCELLED;
+
+ if (unselected) {
+ bGPDlayer *gpl;
+
+ /* hide unselected */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl != layer) {
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ layer->flag |= GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Layer(s)";
+ ot->idname = "GPENCIL_OT_hide";
+ ot->description = "Hide selected/unselected Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_hide_exec;
+ ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
+}
+
+/* ********************** Show All Layers ***************************** */
+
+/* poll callback for showing layers */
+static int gp_reveal_poll(bContext *C)
+{
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gp_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* make all layers visible */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "GPENCIL_OT_reveal";
+ ot->description = "Show all Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_reveal_exec;
+ ot->poll = gp_reveal_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 212d384e5ca..2c6e9d75337 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -21,6 +21,8 @@
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for editing Grease Pencil strokes
*/
/** \file blender/editors/gpencil/gpencil_edit.c
@@ -38,15 +40,10 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
-#include "DNA_anim_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_object_types.h"
-#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -54,17 +51,11 @@
#include "DNA_gpencil_types.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_tracking.h"
#include "UI_interface.h"
@@ -78,454 +69,9 @@
#include "ED_gpencil.h"
#include "ED_view3d.h"
-#include "ED_clip.h"
-#include "ED_keyframing.h"
#include "gpencil_intern.h"
-
-/* ************************************************ */
-/* Context Wrangling... */
-
-/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
-bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
-{
- /* if there's an active area, check if the particular editor may
- * have defined any special Grease Pencil context for editing...
- */
- if (sa) {
- SpaceLink *sl = sa->spacedata.first;
-
- switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View */
- case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
- case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
- {
- BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
- GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
-
- if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
- /* legacy behaviour for usage with old addons requiring object-linked to objects */
-
- /* just in case no active/selected object... */
- if (ob && (ob->flag & SELECT)) {
- /* for now, as long as there's an object, default to using that in 3D-View */
- if (ptr) RNA_id_pointer_create(&ob->id, ptr);
- return &ob->gpd;
- }
- /* else: defaults to scene... */
- }
- else {
- if (ptr) RNA_id_pointer_create(&scene->id, ptr);
- return &scene->gpd;
- }
- break;
- }
- case SPACE_NODE: /* Nodes Editor */
- {
- SpaceNode *snode = (SpaceNode *)sl;
-
- /* return the GP data for the active node block/node */
- if (snode && snode->nodetree) {
- /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
- if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
- return &snode->nodetree->gpd;
- }
-
- /* even when there is no node-tree, don't allow this to flow to scene */
- return NULL;
- }
- case SPACE_SEQ: /* Sequencer */
- {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* for now, Grease Pencil data is associated with the space (actually preview region only) */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
- return &sseq->gpd;
- }
- case SPACE_IMAGE: /* Image/UV Editor */
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- /* for now, Grease Pencil data is associated with the space... */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
- return &sima->gpd;
- }
- case SPACE_CLIP: /* Nodes Editor */
- {
- SpaceClip *sc = (SpaceClip *)sl;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
-
- if (!track)
- return NULL;
-
- if (ptr)
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
-
- return &track->gpd;
- }
- else {
- if (ptr)
- RNA_id_pointer_create(&clip->id, ptr);
-
- return &clip->gpd;
- }
- }
- break;
- }
- default: /* unsupported space */
- return NULL;
- }
- }
-
- /* just fall back on the scene's GP data */
- if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
- return (scene) ? &scene->gpd : NULL;
-}
-
-/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
-{
- ID *screen_id = (ID *)CTX_wm_screen(C);
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- Object *ob = CTX_data_active_object(C);
-
- return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
-}
-
-/* -------------------------------------------------------- */
-
-/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
-}
-
-/* Get the active Grease Pencil datablock */
-bGPdata *ED_gpencil_data_get_active(const bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
-}
-
-/* -------------------------------------------------------- */
-
-// XXX: this should be removed... We really shouldn't duplicate logic like this!
-bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
-{
- Base *base = scene->basact;
- bGPdata *gpd = NULL;
- /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
- * to be consistent with ED_gpencil_data_get_active's behavior.
- */
-
- if (base && TESTBASE(v3d, base)) {
- gpd = base->object->gpd;
- }
- return gpd ? gpd : scene->gpd;
-}
-
-/* ************************************************ */
-/* Panel Operators */
-
-/* poll callback for adding data/layers - special */
-static int gp_add_poll(bContext *C)
-{
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
-}
-
-/* poll callback for checking if there is an active layer */
-static int gp_active_layer_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- return (gpl != NULL);
-}
-
-/* ******************* Add New Data ************************ */
-
-/* add new datablock - wrapper around API */
-static int gp_data_add_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* decrement user count and add new datablock */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_data_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Add New";
- ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_data_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Unlink Data ************************ */
-
-/* poll callback for adding data/layers - special */
-static int gp_data_unlink_poll(bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if we have access to some active data, make sure there's a datablock before enabling this */
- return (gpd_ptr && *gpd_ptr);
-}
-
-
-/* unlink datablock - wrapper around API */
-static int gp_data_unlink_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* just unlink datablock now, decreasing its user count */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = NULL;
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_data_unlink(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Unlink";
- ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_data_unlink_exec;
- ot->poll = gp_data_unlink_poll;
-}
-
-/* ******************* Add New Layer ************************ */
-
-/* add new layer - wrapper around API */
-static int gp_layer_add_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
-
- /* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add New Layer";
- ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_layer_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Remove Active Layer ************************* */
-
-static int gp_layer_remove_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- if (gpl->flag & GP_LAYER_LOCKED) {
- BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
- return OPERATOR_CANCELLED;
- }
-
- /* make the layer before this the new active layer
- * - use the one after if this is the first
- * - if this is the only layer, this naturally becomes NULL
- */
- if (gpl->prev)
- gpencil_layer_setactive(gpd, gpl->prev);
- else
- gpencil_layer_setactive(gpd, gpl->next);
-
- /* delete the layer now... */
- gpencil_layer_delete(gpd, gpl);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Layer";
- ot->idname = "GPENCIL_OT_layer_remove";
- ot->description = "Remove active Grease Pencil layer";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_layer_remove_exec;
- ot->poll = gp_active_layer_poll;
-}
-
-/* ******************* Move Layer Up/Down ************************** */
-
-enum {
- GP_LAYER_MOVE_UP = -1,
- GP_LAYER_MOVE_DOWN = 1
-};
-
-static int gp_layer_move_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- int direction = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- /* up or down? */
- if (direction == GP_LAYER_MOVE_UP) {
- /* up */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
- }
- else {
- /* down */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_move(wmOperatorType *ot)
-{
- static EnumPropertyItem slot_move[] = {
- {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
- {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Grease Pencil Layer";
- ot->idname = "GPENCIL_OT_layer_move";
- ot->description = "Move the active Grease Pencil layer up/down in the list";
-
- /* api callbacks */
- ot->exec = gp_layer_move_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
-}
-
-/* ********************* Duplicate Layer ************************** */
-
-static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- bGPDlayer *new_layer;
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- /* make copy of layer, and add it immediately after the existing layer */
- new_layer = gpencil_layer_duplicate(gpl);
- BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
-
- /* ensure new layer has a unique name, and is now the active layer */
- BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
- gpencil_layer_setactive(gpd, new_layer);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Duplicate Layer";
- ot->idname = "GPENCIL_OT_layer_duplicate";
- ot->description = "Make a copy of the active Grease Pencil layer";
-
- /* callbacks */
- ot->exec = gp_layer_copy_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ************************************************ */
/* Stroke Editing Operators */
@@ -701,7 +247,7 @@ void ED_gpencil_strokes_copybuf_free(void)
BLI_freelinkN(&gp_strokes_copypastebuf, gps);
}
- gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
+ BLI_listbase_clear(&gp_strokes_copypastebuf);
}
/* --------------------- */
@@ -1256,1398 +802,3 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
}
/* ************************************************ */
-/* Grease Pencil to Data Operator */
-
-/* defines for possible modes */
-enum {
- GP_STROKECONVERT_PATH = 1,
- GP_STROKECONVERT_CURVE,
- GP_STROKECONVERT_POLY,
-};
-
-/* Defines for possible timing modes */
-enum {
- GP_STROKECONVERT_TIMING_NONE = 1,
- GP_STROKECONVERT_TIMING_LINEAR = 2,
- GP_STROKECONVERT_TIMING_FULL = 3,
- GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
-};
-
-/* RNA enum define */
-static EnumPropertyItem prop_gpencil_convertmodes[] = {
- {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
- {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
- {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
- {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
- "Use the original timing, but with custom gap lengths (in frames)"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
- bool *UNUSED(r_free))
-{
- if (RNA_boolean_get(ptr, "use_timing_data")) {
- return prop_gpencil_convert_timingmodes;
- }
- return prop_gpencil_convert_timingmodes_restricted;
-}
-
-/* --- */
-
-/* convert the coordinates from the given stroke point into 3d-coordinates
- * - assumes that the active space is the 3D-View
- */
-static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* directly use 3d-coordinates */
- copy_v3_v3(p3d, &pt->x);
- }
- else {
- const float *fp = ED_view3d_cursor3d_get(scene, v3d);
- float mvalf[2];
-
- /* get screen coordinate */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = &ar->v2d;
- UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
- }
- else {
- if (subrect) {
- mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- else {
- mvalf[0] = (float)pt->x / 100.0f * ar->winx;
- mvalf[1] = (float)pt->y / 100.0f * ar->winy;
- }
- }
-
- ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
- }
-}
-
-/* --- */
-
-/* temp struct for gp_stroke_path_animation() */
-typedef struct tGpTimingData {
- /* Data set from operator settings */
- int mode;
- int frame_range; /* Number of frames evaluated for path animation */
- int start_frame, end_frame;
- bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
- float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
- int seed;
-
- /* Data set from points, used to compute final timing FCurve */
- int num_points, cur_point;
-
- /* Distances */
- float *dists;
- float tot_dist;
-
- /* Times */
- float *times; /* Note: Gap times will be negative! */
- float tot_time, gap_tot_time;
- double inittime;
-
- /* Only used during creation of dists & times lists. */
- float offset_time;
-} tGpTimingData;
-
-/* Init point buffers for timing data.
- * Note this assumes we only grow those arrays!
- */
-static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
-{
- float *tmp;
-
- BLI_assert(nbr > gtd->num_points);
-
- /* distances */
- tmp = gtd->dists;
- gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- /* times */
- tmp = gtd->times;
- gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- gtd->num_points = nbr;
-}
-
-/* add stroke point to timing buffers */
-static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
- const float delta_dist)
-{
- float delta_time = 0.0f;
- const int cur_point = gtd->cur_point;
-
- if (!cur_point) {
- /* Special case, first point, if time is not 0.0f we have to compensate! */
- gtd->offset_time = -time;
- gtd->times[cur_point] = 0.0f;
- }
- else if (time < 0.0f) {
- /* This is a gap, negative value! */
- gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
-
- gtd->gap_tot_time += delta_time;
- }
- else {
- gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
- }
-
- gtd->tot_time += delta_time;
- gtd->tot_dist += delta_dist;
- gtd->dists[cur_point] = gtd->tot_dist;
-
- gtd->cur_point++;
-}
-
-/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
- * arbitrarily close points - this is esp. important with NoGaps mode!
- */
-#define MIN_TIME_DELTA 0.02f
-
-/* Loop over next points to find the end of the stroke, and compute */
-static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
- int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
- float *next_delta_time)
-{
- int j;
-
- for (j = idx + 1; j < gtd->num_points; j++) {
- if (gtd->times[j] < 0) {
- gtd->times[j] = -gtd->times[j];
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* In this mode, gap time between this stroke and the next should be 0 currently...
- * So we have to compute its final duration!
- */
- if (gtd->gap_randomness > 0.0f) {
- /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
- * and which sum to exactly tot_gaps_time...
- */
- int rem_gaps = nbr_gaps - (*nbr_done_gaps);
- if (rem_gaps < 2) {
- /* Last gap, just give remaining time! */
- *next_delta_time = tot_gaps_time;
- }
- else {
- float delta, min, max;
-
- /* This code ensures that if the first gaps have been shorter than average gap_duration,
- * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
- */
- delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
-
- /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
- min = -gtd->gap_randomness - delta;
- CLAMP(min, -gtd->gap_randomness, 0.0f);
-
- /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
- max = gtd->gap_randomness - delta;
- CLAMP(max, 0.0f, gtd->gap_randomness);
- *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
- }
- }
- else {
- *next_delta_time += gtd->gap_duration;
- }
- }
- (*nbr_done_gaps)++;
- break;
- }
- }
-
- return j - 1;
-}
-
-static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
-{
- int i;
- float delta_time = 0.0f;
-
- for (i = 0; i < gtd->num_points; i++) {
- if (gtd->times[i] < 0 && i) {
- (*nbr_gaps)++;
- gtd->times[i] = -gtd->times[i] - delta_time;
- delta_time += gtd->times[i] - gtd->times[i - 1];
- gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
- }
- else {
- gtd->times[i] -= delta_time;
- }
- }
- gtd->tot_time -= delta_time;
-
- *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
- gtd->tot_time += *tot_gaps_time;
- if (G.debug & G_DEBUG) {
- printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
- }
- if (gtd->gap_randomness > 0.0f) {
- BLI_rng_srandom(rng, gtd->seed);
- }
-}
-
-static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
- Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
- const int nbr_gaps, const float tot_gaps_time)
-{
- /* Use actual recorded timing! */
- const float time_start = (float)gtd->start_frame;
-
- float last_valid_time = 0.0f;
- int end_stroke_idx = -1, start_stroke_idx = 0;
- float end_stroke_time = 0.0f;
-
- /* CustomGaps specific */
- float delta_time = 0.0f, next_delta_time = 0.0f;
- int nbr_done_gaps = 0;
-
- int i;
- float cfra;
-
- /* This is a bit tricky, as:
- * - We can't add arbitrarily close points on FCurve (in time).
- * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
- */
- for (i = 0; i < gtd->num_points; i++) {
- /* If new stroke... */
- if (i > end_stroke_idx) {
- start_stroke_idx = i;
- delta_time = next_delta_time;
- /* find end of that new stroke */
- end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
- tot_gaps_time, delta_time, &next_delta_time);
- /* This one should *never* be negative! */
- end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
- }
-
- /* Simple proportional stuff... */
- cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
- cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
-
- /* And now, the checks about timing... */
- if (i == start_stroke_idx) {
- /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
- * that the end point of the stroke is far enough!
- * In case it is not, we keep the end point...
- * Note that with CustomGaps mode, this is here we set the actual gap timing!
- */
- if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
- }
- }
- else if (i == end_stroke_idx) {
- /* Always try to insert end point of a curve (should be safe enough, anyway...) */
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else {
- /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
- * and also far enough from (not yet added!) end_stroke keyframe!
- */
- if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
- i, end_stroke_idx);
- }
- }
- }
-}
-
-static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
-{
- Scene *scene = CTX_data_scene(C);
- bAction *act;
- FCurve *fcu;
- PointerRNA ptr;
- PropertyRNA *prop = NULL;
- int nbr_gaps = 0, i;
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
- return;
-
- /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
- gtd->gap_duration = FRA2TIME(gtd->gap_duration);
- gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
-
- /* Enable path! */
- cu->flag |= CU_PATH;
- cu->pathlen = gtd->frame_range;
-
- /* Get RNA pointer to read/write path time values */
- RNA_id_pointer_create((ID *)cu, &ptr);
- prop = RNA_struct_find_property(&ptr, "eval_time");
-
- /* Ensure we have an F-Curve to add keyframes to */
- act = verify_adt_action((ID *)cu, true);
- fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
-
- if (G.debug & G_DEBUG) {
- printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- }
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
- float cfra;
-
- /* Linear extrapolation! */
- fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
-
- cu->ctime = 0.0f;
- cfra = (float)gtd->start_frame;
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
-
- cu->ctime = cu->pathlen;
- if (gtd->realtime) {
- cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- cfra = (float)gtd->end_frame;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- }
- else {
- /* Use actual recorded timing! */
- RNG *rng = BLI_rng_new(0);
- float time_range;
-
- /* CustomGaps specific */
- float tot_gaps_time = 0.0f;
-
- /* Pre-process gaps, in case we don't want to keep their original timing */
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
- }
-
- if (gtd->realtime) {
- time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- time_range = (float)(gtd->end_frame - gtd->start_frame);
- }
-
- if (G.debug & G_DEBUG) {
- printf("GP Stroke Path Conversion: Starting keying!\n");
- }
-
- gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
- nbr_gaps, tot_gaps_time);
-
- BLI_rng_free(rng);
- }
-
- /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
-
- if (G.debug & G_DEBUG) {
- printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- printf("\n\n");
- }
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- /* send updates */
- DAG_id_tag_update(&cu->id, 0);
-}
-
-#undef MIN_TIME_DELTA
-
-#define GAP_DFAC 0.01f
-#define WIDTH_CORR_FAC 0.1f
-#define BEZT_HANDLE_FAC 0.3f
-
-/* convert stroke to 3d path */
-
-/* helper */
-static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bp->vec, p);
- bp->vec[3] = 1.0f;
-
- /* set settings */
- bp->f1 = SELECT;
- bp->radius = width * rad_fac;
- bp->weight = width;
- CLAMP(bp->weight, 0.0f, 1.0f);
- if (bp->weight < minmax_weights[0]) {
- minmax_weights[0] = bp->weight;
- }
- else if (bp->weight > minmax_weights[1]) {
- minmax_weights[1] = bp->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
-}
-
-static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
-{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BPoint *bp, *prev_bp = NULL;
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- int i, old_nbp = 0;
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbp = nu->pntsu;
-
- /* If stitch, the first point of this stroke is already present in current nu.
- * Else, we have to add two additional points to make the zero-radius link between strokes.
- */
- BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->pntsv = 1;
- nu->orderu = 2; /* point-to-point! */
- nu->type = CU_NURBS;
- nu->flagu = CU_NURB_ENDPOINT;
- nu->resolu = cu->resolu;
- nu->resolv = cu->resolv;
- nu->knotsu = NULL;
-
- nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- if (curnu && !stitch && old_nbp) {
- float p1[3], p2[3], p[3], next_p[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- BLI_assert(gps->prev != NULL);
-
- prev_bp = NULL;
- if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bp = &nu->bp[old_nbp - 2];
- }
- bp = &nu->bp[old_nbp - 1];
-
- /* First point */
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (prev_bp) {
- interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
-
- old_nbp += 2;
- }
- else if (add_start_point) {
- float p[3], next_p[3];
- float dt = 0.0f;
-
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- bp = &nu->bp[old_nbp];
- /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
- * would not work (it would be *before* gtd->inittime, which is not supported currently).
- */
- gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
-
- old_nbp++;
- }
-
- if (old_nbp) {
- prev_bp = &nu->bp[old_nbp - 1];
- }
-
- /* add points */
- for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
- i < gps->totpoints;
- i++, pt++, bp++)
- {
- float p[3];
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- /* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
-
- gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
- width, rad_fac, minmax_weights);
-
- prev_bp = bp;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bp->vec);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
- /* Note bp has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
- }
-
- /* add nurb to curve */
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-
- BKE_nurb_knot_calc_u(nu);
-}
-
-/* convert stroke to 3d bezier */
-
-/* helper */
-static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
- const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bezt->vec[0], h1);
- copy_v3_v3(bezt->vec[1], p);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* set settings */
- bezt->h1 = bezt->h2 = HD_FREE;
- bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
- bezt->radius = width * rad_fac;
- bezt->weight = width;
- CLAMP(bezt->weight, 0.0f, 1.0f);
- if (bezt->weight < minmax_weights[0]) {
- minmax_weights[0] = bezt->weight;
- }
- else if (bezt->weight > minmax_weights[1]) {
- minmax_weights[1] = bezt->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
-}
-
-static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
-{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BezTriple *bezt, *prev_bezt = NULL;
- int i, tot, old_nbezt = 0;
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbezt = nu->pntsu;
- /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
- * so no need to add it.
- * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
- */
- BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->resolu = 12;
- nu->resolv = 12;
- nu->type = CU_BEZIER;
- nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- tot = gps->totpoints;
-
- /* get initial coordinates */
- pt = gps->points;
- if (tot) {
- gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
- if (tot > 1) {
- gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
- }
- if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- if (curnu && old_nbezt) {
- BLI_assert(gps->prev != NULL);
-
- /* Update last point's second handle */
- if (stitch) {
- bezt = &nu->bezt[old_nbezt - 1];
- interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
- pt++;
- }
-
- /* Create "link points" */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- else {
- float p1[3], p2[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- prev_bezt = NULL;
- if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bezt = &nu->bezt[old_nbezt - 2];
- }
- bezt = &nu->bezt[old_nbezt - 1];
-
- /* First point */
- if (prev_bezt) {
- interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (tot > 1) {
- interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second handle of last point of previous stroke. */
- interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* First point */
- interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt += 2;
- copy_v3_v3(p3d_prev, p2);
- }
- }
- else if (add_start_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, p3d_cur);
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
- bezt = &nu->bezt[old_nbezt];
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt++;
- copy_v3_v3(p3d_prev, p);
- }
-
- if (old_nbezt) {
- prev_bezt = &nu->bezt[old_nbezt - 1];
- }
-
- /* add points */
- for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- if (i || old_nbezt) {
- interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
- }
-
- if (i < tot - 1) {
- interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
- }
-
- gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
- do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
-
- /* shift coord vects */
- copy_v3_v3(p3d_prev, p3d_cur);
- copy_v3_v3(p3d_cur, p3d_next);
-
- if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
-
- prev_bezt = bezt;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bezt->vec[1]);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
-
- /* Second handle of last point of this stroke. */
- interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
- copy_v3_v3(prev_bezt->vec[2], h2);
-
- /* The end point */
- interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
- /* Note bezt has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
- }
-
- /* must calculate handles or else we crash */
- BKE_nurb_handles_calc(nu);
-
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-}
-
-#undef GAP_DFAC
-#undef WIDTH_CORR_FAC
-#undef BEZT_HANDLE_FAC
-
-static void gp_stroke_finalize_curve_endpoints(Curve *cu)
-{
- /* start */
- Nurb *nu = cu->nurb.first;
- int i = 0;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-
- /* end */
- nu = cu->nurb.last;
- i = nu->pntsu - 1;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-}
-
-static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
-{
- Nurb *nu;
- const float delta = minmax_weights[0];
- float fac;
- int i;
-
- /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
- if (IS_EQF(delta, minmax_weights[1]))
- fac = 1.0f;
- else
- fac = 1.0f / (minmax_weights[1] - delta);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- bezt->weight = (bezt->weight - delta) * fac;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu; i++, bp++) {
- bp->weight = (bp->weight - delta) * fac;
- }
- }
- }
-}
-
-static int gp_camera_view_subrect(bContext *C, rctf *subrect)
-{
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (v3d) {
- RegionView3D *rv3d = ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- Scene *scene = CTX_data_scene(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
- return 1;
- }
- }
-
- return 0;
-}
-
-/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
-static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
- const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
-{
- struct Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
- bGPDstroke *gps, *prev_gps = NULL;
- Object *ob;
- Curve *cu;
- Nurb *nu = NULL;
- Base *base_orig = BASACT, *base_new = NULL;
- float minmax_weights[2] = {1.0f, 0.0f};
-
- /* camera framing */
- rctf subrect, *subrect_ptr = NULL;
-
- /* error checking */
- if (ELEM(NULL, gpd, gpl, gpf))
- return;
-
- /* only convert if there are any strokes on this layer's frame to convert */
- if (BLI_listbase_is_empty(&gpf->strokes))
- return;
-
- /* initialize camera framing */
- if (gp_camera_view_subrect(C, &subrect)) {
- subrect_ptr = &subrect;
- }
-
- /* init the curve object (remove rotation and get curve data from it)
- * - must clear transforms set on object, as those skew our results
- */
- ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
- cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- base_new = BKE_scene_base_add(scene, ob);
-
- cu->flag |= CU_3D;
-
- gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
-
- /* add points to curve */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- const bool add_start_point = (link_strokes && !(prev_gps));
- const bool add_end_point = (link_strokes && !(gps->next));
-
- /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
- bool stitch = false;
- if (prev_gps) {
- bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
- bGPDspoint *pt2 = &gps->points[0];
-
- if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
- stitch = true;
- }
- }
-
- /* Decide whether we connect this stroke to previous one */
- if (!(stitch || link_strokes)) {
- nu = NULL;
- }
-
- switch (mode) {
- case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- case GP_STROKECONVERT_CURVE:
- case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- default:
- BLI_assert(!"invalid mode");
- break;
- }
- prev_gps = gps;
- }
-
- /* If link_strokes, be sure first and last points have a zero weight/size! */
- if (link_strokes) {
- gp_stroke_finalize_curve_endpoints(cu);
- }
-
- /* Update curve's weights, if needed */
- if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
- gp_stroke_norm_curve_weights(cu, minmax_weights);
- }
-
- /* Create the path animation, if needed */
- gp_stroke_path_animation(C, reports, cu, gtd);
-
- if (mode == GP_STROKECONVERT_POLY) {
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- BKE_nurb_type_convert(nu, CU_POLY, false);
- }
- }
-
- /* set the layer and select */
- base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
- base_new->flag = ob->flag = base_new->flag | SELECT;
-}
-
-/* --- */
-
-/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
- * op may be NULL.
- */
-static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = NULL;
- bGPDstroke *gps = NULL;
- bGPDspoint *pt;
- double base_time, cur_time, prev_time = -1.0;
- int i;
- bool valid = true;
-
- if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
- return false;
-
- do {
- base_time = cur_time = gps->inittime;
- if (cur_time <= prev_time) {
- valid = false;
- break;
- }
-
- prev_time = cur_time;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- cur_time = base_time + (double)pt->time;
- /* First point of a stroke should have the same time as stroke's inittime,
- * so it's the only case where equality is allowed!
- */
- if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
- valid = false;
- break;
- }
- prev_time = cur_time;
- }
-
- if (!valid) {
- break;
- }
- } while ((gps = gps->next));
-
- if (op) {
- RNA_boolean_set(op->ptr, "use_timing_data", valid);
- }
- return valid;
-}
-
-/* Check end_frame is always > start frame! */
-static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
-{
- int start_frame = RNA_int_get(ptr, "start_frame");
- int end_frame = RNA_int_get(ptr, "end_frame");
-
- if (end_frame <= start_frame) {
- RNA_int_set(ptr, "end_frame", start_frame + 1);
- }
-}
-
-static int gp_convert_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = NULL;
- bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
-
- /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
- * and if we are not in edit mode!
- */
- return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = gpencil_layer_getactive(gpd)) &&
- (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
- (gpf->strokes.first) &&
- (scene->obedit == NULL));
-}
-
-static int gp_convert_layer_exec(bContext *C, wmOperator *op)
-{
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- Scene *scene = CTX_data_scene(C);
- const int mode = RNA_enum_get(op->ptr, "type");
- const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
- const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
- const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
- bool valid_timing;
- tGpTimingData gtd;
-
- /* check if there's data to work with */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
- return OPERATOR_CANCELLED;
- }
-
- if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
- BKE_report(op->reports, RPT_WARNING,
- "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
- }
- valid_timing = RNA_property_boolean_get(op->ptr, prop);
-
- gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
- /* Check for illegal timing mode! */
- if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
- gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
- RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
- }
- if (!link_strokes) {
- gtd.mode = GP_STROKECONVERT_TIMING_NONE;
- }
-
- /* grab all relevant settings */
- gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
- gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
- gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
- gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
- gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
- gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
- gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
- gtd.seed = RNA_int_get(op->ptr, "seed");
- gtd.num_points = gtd.cur_point = 0;
- gtd.dists = gtd.times = NULL;
- gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
- gtd.inittime = 0.0;
- gtd.offset_time = 0.0f;
-
- /* perform conversion */
- gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
-
- /* free temp memory */
- if (gtd.dists) {
- MEM_freeN(gtd.dists);
- gtd.dists = NULL;
- }
- if (gtd.times) {
- MEM_freeN(gtd.times);
- gtd.times = NULL;
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
-{
- const char *prop_id = RNA_property_identifier(prop);
- const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
- int timing_mode = RNA_enum_get(ptr, "timing_mode");
- bool realtime = RNA_boolean_get(ptr, "use_realtime");
- float gap_duration = RNA_float_get(ptr, "gap_duration");
- float gap_randomness = RNA_float_get(ptr, "gap_randomness");
- const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
-
- /* Always show those props */
- if (STREQ(prop_id, "type") ||
- STREQ(prop_id, "use_normalize_weights") ||
- STREQ(prop_id, "radius_multiplier") ||
- STREQ(prop_id, "use_link_strokes"))
- {
- return true;
- }
-
- /* Never show this prop */
- if (STREQ(prop_id, "use_timing_data"))
- return false;
-
- if (link_strokes) {
- /* Only show when link_stroke is true */
- if (STREQ(prop_id, "timing_mode"))
- return true;
-
- if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
- /* Only show when link_stroke is true and stroke timing is enabled */
- if (STREQ(prop_id, "frame_range") ||
- STREQ(prop_id, "start_frame"))
- {
- return true;
- }
-
- /* Only show if we have valid timing data! */
- if (valid_timing && STREQ(prop_id, "use_realtime"))
- return true;
-
- /* Only show if realtime or valid_timing is false! */
- if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
- return true;
-
- if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* Only show for custom gaps! */
- if (STREQ(prop_id, "gap_duration"))
- return true;
-
- /* Only show randomness for non-null custom gaps! */
- if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
- return true;
-
- /* Only show seed for randomize action! */
- if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
- return true;
- }
- }
- }
-
- /* Else, hidden! */
- return false;
-}
-
-static void gp_convert_ui(bContext *C, wmOperator *op)
-{
- uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- /* Main auto-draw call */
- uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
-}
-
-void GPENCIL_OT_convert(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Convert Grease Pencil";
- ot->idname = "GPENCIL_OT_convert";
- ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_convert_layer_exec;
- ot->poll = gp_convert_poll;
- ot->ui = gp_convert_ui;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
-
- RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
- "Normalize weight (set from stroke width)");
- RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
- "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
- "Whether to link strokes with zero-radius sections of curves");
-
- prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
- "Timing Mode", "How to use timing data stored in strokes");
- RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
-
- RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
- "The duration of evaluation of the path control curve", 1, 1000);
- RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
- "The start frame of the path control curve", 1, 100000);
- RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
- "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
- prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
- "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
- RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
-
- RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
- "Custom Gap mode: (Average) length of gaps, in frames "
- "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
- "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
- "Custom Gap mode: Random generator seed", 0, 100);
-
- /* Note: Internal use, this one will always be hidden by UI code... */
- prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
- "Whether the converted Grease Pencil layer has valid timing data (internal use)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 56420434494..72cd9022d69 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -96,6 +96,12 @@ void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
+/* Poll Callbacks ------------------------------------ */
+/* gpencil_utils.c */
+
+int gp_add_poll(struct bContext *C);
+int gp_active_layer_poll(struct bContext *C);
+
/* ***************************************************** */
/* Operator Defines */
@@ -138,6 +144,9 @@ void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_reveal(struct wmOperatorType *ot);
+
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 3fae208a2e2..4752f3dbb36 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -34,8 +34,6 @@
#include "BLI_sys_types.h"
-#include "BLI_blenlib.h"
-
#include "BKE_context.h"
#include "DNA_gpencil_types.h"
@@ -183,7 +181,18 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
#ifdef __APPLE__
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
+#endif
+
+ /* Show/Hide */
+ /* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", true);
+
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -262,6 +271,9 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_move);
WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+ WM_operatortype_append(GPENCIL_OT_hide);
+ WM_operatortype_append(GPENCIL_OT_reveal);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index c8774cb73a1..f3eb1612576 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "DNA_object_types.h"
@@ -1030,6 +1031,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* set current area
* - must verify that region data is 3D-view (and not something else)
*/
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
@@ -1252,6 +1254,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
/* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
if (p->sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = p->sa->spacedata.first;
@@ -1437,12 +1440,14 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
gpencil_draw_toggle_eraser_cursor(C, p, false);
-
- /* if successful, store the new eraser size to be used again next time */
- if (p->status == GP_STATUS_DONE)
- U.gp_eraser = p->radius;
}
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
/* cleanup */
gp_paint_cleanup(p);
gp_session_cleanup(p);
@@ -1493,6 +1498,15 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
/* ------------------------------- */
+/* ensure that the correct cursor icon is set */
+static void gpencil_draw_cursor_set(tGPsdata *p)
+{
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+}
+
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(tGPsdata *p)
{
@@ -1608,7 +1622,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
/* handle pressure sensitivity (which is supplied by tablets) */
if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ const wmTabletData *wmtab = event->tablet_data;
tablet = (wmtab->Active != EVT_TABLET_NONE);
p->pressure = wmtab->Pressure;
@@ -1733,7 +1747,6 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = NULL;
- wmWindow *win = CTX_wm_window(C);
if (G.debug & G_DEBUG)
printf("GPencil - Starting Drawing\n");
@@ -1759,11 +1772,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
- /* set cursor */
- if (p->paintmode == GP_PAINTMODE_ERASER)
- WM_cursor_modal_set(win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(win, BC_PAINTBRUSHCURSOR);
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
+ */
+ gpencil_draw_cursor_set(p);
/* only start drawing immediately if we're allowed to do so... */
if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
@@ -1777,6 +1790,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
/* toolbar invoked - don't start drawing yet... */
/* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -1814,8 +1828,10 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
if (gp_session_initdata(C, p))
gp_paint_initstroke(p, p->paintmode);
- if (p->status != GP_STATUS_ERROR)
+ if (p->status != GP_STATUS_ERROR) {
p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
return op->customdata;
}
@@ -1831,6 +1847,7 @@ static void gpencil_stroke_end(wmOperator *op)
gp_session_cleanup(p);
p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
p->gpd = NULL;
p->gpl = NULL;
@@ -1856,6 +1873,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* in 3D space.
*/
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
/* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
if (ISKEYBOARD(event->type)) {
if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
@@ -1885,8 +1907,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
*/
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE)) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (event->val != KM_NOTHING)) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
int sketch = 0;
@@ -1937,29 +1960,88 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event->val == KM_PRESS) {
- /* Switch paintmode (temporarily if need be) based on which button was used
- * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
*/
- if (event->type == LEFTMOUSE) {
- /* restore drawmode to default */
- p->paintmode = RNA_enum_get(op->ptr, "mode");
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region, p->ar, event->x, event->y,
+ p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
}
- else if (event->type == RIGHTMOUSE) {
- /* turn on eraser */
- p->paintmode = GP_PAINTMODE_ERASER;
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
}
-
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
-
- /* not painting, so start stroke (this should be mouse-button down) */
- p = gpencil_stroke_begin(C, op);
- if (p->status == GP_STATUS_ERROR) {
- estate = OPERATOR_CANCELLED;
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+ else if (event->type == RIGHTMOUSE) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ 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
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
}
}
else {
p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
}
@@ -2023,9 +2105,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
if (0 == gpencil_area_exists(C, p->sa))
estate = OPERATOR_CANCELLED;
- else
+ else {
/* update status indicators - cursor, header, etc. */
gpencil_draw_status_indicators(p);
+ gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
+ }
/* process last operations before exiting */
switch (estate) {
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 9ba77a4244e..1b66f366b70 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -35,28 +35,16 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_lasso.h"
#include "BLI_utildefines.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_context.h"
-#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
#include "UI_interface.h"
@@ -69,8 +57,6 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
-#include "ED_view3d.h"
-#include "ED_keyframing.h"
#include "gpencil_intern.h"
@@ -789,6 +775,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPDstroke *hit_stroke = NULL;
bGPDspoint *hit_point = NULL;
+ int hit_distance = radius_squared;
/* sanity checks */
if (sa == NULL) {
@@ -811,7 +798,6 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
{
bGPDspoint *pt;
int i;
- int hit_index = -1;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -821,18 +807,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, x0, x0)) {
- /* only check if point is inside */
- if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius_squared) {
- hit_stroke = gps;
- hit_point = pt;
- break;
+ const int pt_distance = ((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my));
+
+ /* check if point is inside */
+ if (pt_distance <= radius_squared) {
+ /* only use this point if it is a better match than the current hit - T44685 */
+ if (pt_distance < hit_distance) {
+ hit_stroke = gps;
+ hit_point = pt;
+ hit_distance = pt_distance;
+ }
}
}
}
-
- /* skip to next stroke if nothing found */
- if (hit_index == -1)
- continue;
}
CTX_DATA_END;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 289cbc568d2..0d7aac7f48f 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -32,8 +32,6 @@
#include <stddef.h>
#include <math.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -46,18 +44,10 @@
#include "DNA_view3d_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-
-#include "UI_interface.h"
+#include "BKE_tracking.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -65,11 +55,183 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
+#include "ED_clip.h"
#include "ED_view3d.h"
#include "gpencil_intern.h"
/* ******************************************************** */
+/* Context Wrangling... */
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
+bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
+{
+ /* if there's an active area, check if the particular editor may
+ * have defined any special Grease Pencil context for editing...
+ */
+ if (sa) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3D-View */
+ case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
+ case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
+ {
+ BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
+ GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
+
+ if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
+ /* legacy behaviour for usage with old addons requiring object-linked to objects */
+
+ /* just in case no active/selected object... */
+ if (ob && (ob->flag & SELECT)) {
+ /* for now, as long as there's an object, default to using that in 3D-View */
+ if (ptr) RNA_id_pointer_create(&ob->id, ptr);
+ return &ob->gpd;
+ }
+ /* else: defaults to scene... */
+ }
+ else {
+ if (ptr) RNA_id_pointer_create(&scene->id, ptr);
+ return &scene->gpd;
+ }
+ break;
+ }
+ case SPACE_NODE: /* Nodes Editor */
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ /* return the GP data for the active node block/node */
+ if (snode && snode->nodetree) {
+ /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
+ if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
+ return &snode->nodetree->gpd;
+ }
+
+ /* even when there is no node-tree, don't allow this to flow to scene */
+ return NULL;
+ }
+ case SPACE_SEQ: /* Sequencer */
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* for now, Grease Pencil data is associated with the space (actually preview region only) */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
+ return &sseq->gpd;
+ }
+ case SPACE_IMAGE: /* Image/UV Editor */
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ /* for now, Grease Pencil data is associated with the space... */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
+ return &sima->gpd;
+ }
+ case SPACE_CLIP: /* Nodes Editor */
+ {
+ SpaceClip *sc = (SpaceClip *)sl;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip) {
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+
+ if (!track)
+ return NULL;
+
+ if (ptr)
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
+
+ return &track->gpd;
+ }
+ else {
+ if (ptr)
+ RNA_id_pointer_create(&clip->id, ptr);
+
+ return &clip->gpd;
+ }
+ }
+ break;
+ }
+ default: /* unsupported space */
+ return NULL;
+ }
+ }
+
+ /* just fall back on the scene's GP data */
+ if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
+ return (scene) ? &scene->gpd : NULL;
+}
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
+bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+{
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
+
+ return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
+}
+
+/* -------------------------------------------------------- */
+
+/* Get the active Grease Pencil datablock, when context is not available */
+bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* Get the active Grease Pencil datablock */
+bGPdata *ED_gpencil_data_get_active(const bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* -------------------------------------------------------- */
+
+// XXX: this should be removed... We really shouldn't duplicate logic like this!
+bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
+{
+ Base *base = scene->basact;
+ bGPdata *gpd = NULL;
+ /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
+ * to be consistent with ED_gpencil_data_get_active's behavior.
+ */
+
+ if (base && TESTBASE(v3d, base)) {
+ gpd = base->object->gpd;
+ }
+ return gpd ? gpd : scene->gpd;
+}
+
+/* ******************************************************** */
+/* Poll Callbacks */
+
+/* poll callback for adding data/layers - special */
+int gp_add_poll(bContext *C)
+{
+ /* the base line we have is that we have somewhere to add Grease Pencil data */
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+}
+
+/* poll callback for checking if there is an active layer */
+int gp_active_layer_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ return (gpl != NULL);
+}
+
+/* ******************************************************** */
+/* Brush Tool Core */
/* Check if part of stroke occurs within last segment drawn by eraser */
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
@@ -89,6 +251,7 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
}
/* ******************************************************** */
+/* Stroke Validity Testing */
/* Check whether given stroke can be edited given the supplied context */
// XXX: do we need additional flags for screenspace vs dataspace?
@@ -125,6 +288,7 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
}
/* ******************************************************** */
+/* Space Conversion */
/* Init handling for space-conversion function (from passed-in parameters) */
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 4dc39681ed2..b904417cfcb 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -181,8 +181,8 @@ typedef struct gla2DDrawInfo gla2DDrawInfo;
#if 0
gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect);
-void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r);
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2]);
+void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y);
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]);
void glaEnd2DDraw(gla2DDrawInfo *di);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 50581429700..0f70bf3c745 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -49,7 +49,6 @@ struct Object;
struct bDopeSheet;
struct bAction;
-struct bActionGroup;
struct FCurve;
struct FModifier;
@@ -115,13 +114,17 @@ typedef struct bAnimListElem {
int flag; /* copy of elem's flags for quick access */
int index; /* for un-named data, the index of the data in its collection */
- short update; /* (eAnim_Update_Flags) tag the element for updating */
+ char update; /* (eAnim_Update_Flags) tag the element for updating */
+ char tag; /* tag the included data. Temporary always */
+
short datatype; /* (eAnim_KeyType) type of motion data to expect */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
struct ID *id; /* ID block that channel is attached to */
struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */
+
+ void *owner; /* for per-element F-Curves (e.g. NLA Control Curves), the element that this represents (e.g. NlaStrip) */
} bAnimListElem;
@@ -141,6 +144,9 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_GROUP,
ANIMTYPE_FCURVE,
+ ANIMTYPE_NLACONTROLS,
+ ANIMTYPE_NLACURVE,
+
ANIMTYPE_FILLACTD,
ANIMTYPE_FILLDRIVERS,
@@ -450,13 +456,13 @@ typedef struct bAnimChannelType {
/* ------------------------ Drawing API -------------------------- */
/* Get typeinfo for the given channel */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
/* Print debugging info about a given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc);
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
/* Draw the widgets for the given channel */
void ANIM_channel_draw_widgets(const struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index);
@@ -611,7 +617,7 @@ typedef enum eAnimUnitConv_Flags {
short ANIM_get_normalization_flags(bAnimContext *ac);
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag);
+float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
/* ------------- Utility macros ----------------------- */
@@ -653,6 +659,7 @@ void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
/* ************************************************* */
/* OPERATORS */
@@ -670,6 +677,14 @@ void ED_operatormacros_graph(void);
void ED_operatormacros_action(void);
/* ************************************************ */
+/* Animation Editor Exports */
+/* XXX: Should we be doing these here, or at all? */
+
+/* Action Editor - Action Management */
+struct AnimData *ED_actedit_animdata_from_context(struct bContext *C);
+void ED_animedit_unlink_action(struct bContext *C, struct ID *id, struct AnimData *adt, struct bAction *act, struct ReportList *reports);
+
+/* ************************************************ */
#endif /* __ED_ANIM_API_H__ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index b08cc12dc3e..35bb12ddaad 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -39,16 +39,12 @@ struct Base;
struct bContext;
struct Bone;
struct bPoseChannel;
-struct DerivedMesh;
struct IDProperty;
struct ListBase;
struct MeshDeformModifierData;
struct Object;
-struct RegionView3D;
struct ReportList;
struct Scene;
-struct SK_Sketch;
-struct View3D;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
@@ -59,8 +55,6 @@ typedef struct EditBone {
struct EditBone *parent; /* Editbones have a one-way link (i.e. children refer
* to parents. This is converted to a two-way link for
* normal bones when leaving editmode. */
- void *temp; /* Used to store temporary data */
-
char name[64]; /* MAXBONENAME */
float roll; /* Roll along axis. We'll ultimately use the axis/angle method
* for determining the transformation matrix of the bone. The axis
@@ -83,6 +77,14 @@ typedef struct EditBone {
float oldlength; /* for envelope scaling */
short segments;
+
+ /* Used to store temporary data */
+ union {
+ struct EditBone *ebone;
+ struct Bone *bone;
+ void *p;
+ int i;
+ } temp;
} EditBone;
#define BONESEL_ROOT (1 << 28)
@@ -119,10 +121,12 @@ void ED_keymap_armature(struct wmKeyConfig *keyconf);
void ED_armature_from_edit(struct bArmature *arm);
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
-void ED_armature_deselect_all(struct Object *obedit, int toggle);
+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,
+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 mouse_armature(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 64c16605dec..9a987d7618c 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,4 +37,6 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
+void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
+
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 27e9cad4fd5..fee3d44b8eb 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -31,13 +31,10 @@
#ifndef __ED_CURVE_H__
#define __ED_CURVE_H__
-struct Base;
struct bContext;
struct Nurb;
struct Object;
-struct Scene;
struct Text;
-struct View3D;
struct wmOperator;
struct wmKeyConfig;
struct Curve;
@@ -79,7 +76,7 @@ void free_editText(struct Object *obedit);
void ED_text_to_object(struct bContext *C, struct Text *text, const bool split_lines);
-bool ED_curve_select_nth(struct Curve *cu, int nth);
+bool ED_curve_select_nth(struct Curve *cu, int nth, int skip, int offset);
void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, struct BezTriple *src, int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index c4f08ca4775..448f2c83aad 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -33,19 +33,15 @@
struct ID;
struct ListBase;
struct bContext;
-struct bScreen;
struct ScrArea;
struct ARegion;
struct View3D;
-struct SpaceNode;
-struct SpaceSeq;
struct Object;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct PointerRNA;
-struct ImBuf;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 704876e1261..f49d4b508c6 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -31,13 +31,11 @@
#define __ED_IMAGE_H__
struct SpaceImage;
-struct Main;
struct bContext;
struct Image;
struct ImageUser;
struct ImBuf;
struct ToolSettings;
-struct uiBlock;
struct wmWindowManager;
struct ARegion;
struct Scene;
@@ -49,7 +47,7 @@ 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]);
-struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **lock_r);
+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_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 0359153317b..7d163da0db0 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -34,7 +34,6 @@
struct bAnimContext;
struct AnimData;
-struct BezTriple;
struct FCurve;
struct bDopeSheet;
struct bAction;
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index e5b5e79875d..5d76c9e0f6f 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -46,10 +46,8 @@ struct FCurve;
struct BezTriple;
struct bPoseChannel;
-struct bConstraint;
struct bContext;
-struct wmOperatorType;
struct ReportList;
struct PointerRNA;
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6636319dc9b..6fe1524cb6d 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -32,7 +32,6 @@
#define __ED_LATTICE_H__
struct Object;
-struct Lattice;
void free_editLatt(struct Object *ob);
void make_editLatt(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 97fd553ea19..1f13b46ff2a 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -31,10 +31,10 @@
#ifndef __ED_MASK_H__
#define __ED_MASK_H__
+struct bContext;
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
-struct wmEvent;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
@@ -49,6 +49,7 @@ void ED_mask_point_pos__reverse(struct ScrArea *sa, struct ARegion *ar,
float x, float y, float *xr, float *yr);
void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]);
+bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
void ED_operatortypes_mask(void);
void ED_keymap_mask(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 5e774c63841..05a4ccabd1b 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -32,7 +32,6 @@
#define __ED_MBALL_H__
struct bContext;
-struct MetaBall;
struct Object;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index ccf97221112..8e19ec839d8 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -40,39 +40,27 @@ struct View3D;
struct ARegion;
struct bContext;
struct wmOperator;
-struct wmWindowManager;
struct wmKeyConfig;
struct ReportList;
-struct EditSelection;
struct ViewContext;
struct bDeformGroup;
-struct MDeformWeight;
struct MDeformVert;
struct Scene;
struct Mesh;
-struct MFace;
-struct MEdge;
-struct MVert;
-struct MCol;
struct UvVertMap;
struct UvMapVert;
-struct CustomData;
struct BMEditMesh;
-struct BMEditSelection;
struct BMesh;
struct BMVert;
struct BMLoop;
struct BMBVHTree;
-struct MLoopCol;
struct BMEdge;
struct BMFace;
struct UvVertMap;
struct UvMapVert;
struct ToolSettings;
-struct Material;
struct Object;
struct rcti;
-struct MeshStatVis;
/* editmesh_utils.c */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis,
@@ -119,7 +107,9 @@ void EDBM_mesh_reveal(struct BMEditMesh *em);
void EDBM_update_generic(struct BMEditMesh *em, const bool do_tessface, const bool is_destructive);
-struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const bool selected, const bool do_islands);
+struct UvElementMap *BM_uv_element_map_create(
+ struct BMesh *bm,
+ const bool selected, const bool use_winding, const bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *vmap);
struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l);
@@ -128,7 +118,9 @@ struct MTexPoly *EDBM_mtexpoly_active_get(struct BMEditMesh *em, struct BMFace *
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
-struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, const float limit[2]);
+struct UvVertMap *BM_uv_vert_map_create(
+ struct BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding);
void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
@@ -149,9 +141,27 @@ bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, const int mcords[][2]
short xmin, short ymin, short xmax, short ymax);
bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads);
-struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist, const bool sel, const bool strict);
-struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist);
-struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist);
+struct BMVert *EDBM_vert_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle);
+struct BMVert *EDBM_vert_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMEdge *EDBM_edge_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMEdge **r_eed_zbuf);
+struct BMEdge *EDBM_edge_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMFace *EDBM_face_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMFace **r_efa_zbuf);
+struct BMFace *EDBM_face_find_nearest(
+ struct ViewContext *vc, float *r_dist);
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
@@ -233,6 +243,11 @@ void ED_vgroup_parray_mirror_assign(struct Object *ob,
void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array, const int dvert_tot,
const bool *vgroup_validmap, const int vgroup_tot,
const float epsilon, const bool keep_single);
+void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array, const int dvert_tot,
+ float *dvert_weights, const int def_nr);
+void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array, const int dvert_tot,
+ const float *dvert_weights, const int def_nr,
+ const bool remove_zero);
void ED_vgroup_mirror(struct Object *ob,
const bool mirror_weights, const bool flip_vgroups,
const bool all_vgroups, const bool use_topology,
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 824c82a0069..1445308c485 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -33,7 +33,6 @@
struct ID;
struct Main;
-struct Material;
struct Scene;
struct Tex;
struct bContext;
@@ -104,6 +103,8 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
+void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
+
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 295bb752a08..c62bdc1ba87 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -35,33 +35,17 @@
extern "C" {
#endif
-struct BMEdge;
-struct BMFace;
-struct BMVert;
-struct BPoint;
struct Base;
-struct BezTriple;
-struct Curve;
-struct EditBone;
struct EnumPropertyItem;
struct ID;
-struct KeyBlock;
-struct Lattice;
struct Main;
-struct Mesh;
-struct MetaElem;
struct ModifierData;
-struct HookModifierData;
-struct Nurb;
struct Object;
struct ReportList;
struct Scene;
-struct View3D;
-struct ViewContext;
struct bConstraint;
struct bContext;
struct bPoseChannel;
-struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
@@ -93,7 +77,7 @@ typedef enum eParentType {
PAR_PATH_CONST,
PAR_LATTICE,
PAR_VERTEX,
- PAR_VERTEX_TRI
+ PAR_VERTEX_TRI,
} eParentType;
#ifdef __RNA_TYPES_H__
@@ -147,6 +131,10 @@ float ED_object_new_primitive_matrix(
struct bContext *C, struct Object *editob,
const float loc[3], const float rot[3], float primmat[4][4]);
+
+/* Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise). */
+#define OBJECT_ADD_SIZE_MAXF 1.0e12f
+
void ED_object_add_unit_props(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, const char view_align_axis,
@@ -154,8 +142,10 @@ bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, c
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
struct Object *ED_object_add_type(
- struct bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer) ATTR_RETURNS_NONNULL;
+ struct bContext *C,
+ int type, const char *name, const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
+ ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
void ED_object_single_users(struct Main *bmain, struct Scene *scene, const bool full, const bool copy_groups);
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
@@ -175,6 +165,9 @@ void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con)
void ED_object_constraint_update(struct Object *ob);
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob);
+void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con);
+void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con);
+
/* object_lattice.c */
bool mouse_lattice(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
void undo_push_lattice(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
new file mode 100644
index 00000000000..af4af8e2f5d
--- /dev/null
+++ b/source/blender/editors/include/ED_outliner.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_outliner.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_OUTLINER_H__
+#define __ED_OUTLINER_H__
+
+struct ID;
+struct SpaceOops;
+
+/* Used to check whether a given texture context is valid in current context. */
+void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
+
+#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index decd79fcc7b..e46f4b966c0 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -26,7 +26,6 @@
#define __ED_PAINT_H__
struct bContext;
-struct RegionView3D;
struct wmKeyConfig;
struct wmOperator;
@@ -47,9 +46,9 @@ typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_step_num(struct bContext *C, int type, int num);
-const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *active);
+const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active);
void ED_undo_paint_free(void);
-int ED_undo_paint_valid(int type, const char *name);
+bool ED_undo_paint_is_valid(int type, const char *name);
bool ED_undo_paint_empty(int type);
void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
void ED_undo_paint_push_end(int type);
@@ -59,7 +58,7 @@ void ED_undo_paint_push_end(int type);
void ED_image_undo_restore(struct bContext *C, struct ListBase *lb);
void ED_image_undo_free(struct ListBase *lb);
void ED_imapaint_clear_partial_redraw(void);
-void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index f9516f255cf..6cb8c0cfb19 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -35,10 +35,7 @@
struct bContext;
struct Object;
struct ParticleEditSettings;
-struct ParticleSystem;
-struct RadialControl;
struct rcti;
-struct wmKeyConfig;
struct PTCacheEdit;
struct Scene;
@@ -69,9 +66,9 @@ void PE_undo_push(struct Scene *scene, const char *str);
void PE_undo_step(struct Scene *scene, int step);
void PE_undo(struct Scene *scene);
void PE_redo(struct Scene *scene);
-int PE_undo_valid(struct Scene *scene);
+bool PE_undo_is_valid(struct Scene *scene);
void PE_undo_number(struct Scene *scene, int nr);
-const char *PE_undo_get_name(struct Scene *scene, int nr, int *active);
+const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active);
#endif /* __ED_PARTICLE_H__ */
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 293621c3d19..ba58ae60b15 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -37,9 +37,6 @@ struct MTex;
struct Render;
struct Scene;
struct ScrArea;
-struct RegionView3D;
-struct RenderEngine;
-struct View3D;
struct wmWindowManager;
/* render_ops.c */
@@ -50,7 +47,7 @@ void ED_operatortypes_render(void);
void ED_render_id_flush_update(struct Main *bmain, struct ID *id);
void ED_render_engine_changed(struct Main *bmain);
-void ED_render_engine_area_exit(struct ScrArea *sa);
+void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database);
@@ -63,17 +60,21 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
* - PR_NODE_RENDER: preview is rendered for node editor
+ * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
-#define PR_BUTS_RENDER 0
-#define PR_ICON_RENDER 1
-#define PR_NODE_RENDER 2
+enum {
+ PR_BUTS_RENDER = 0,
+ PR_ICON_RENDER = 1,
+ PR_NODE_RENDER = 2,
+ PR_ICON_DEFERRED = 3,
+};
void ED_preview_init_dbase(void);
void ED_preview_free_dbase(void);
void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method);
-void ED_preview_icon_render(struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey);
+void ED_preview_icon_render(struct Main *bmain, struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey);
void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey);
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 8c33395cc49..441a9bdb1c1 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -42,7 +42,6 @@ struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
struct bContext;
-struct SpaceType;
struct Scene;
struct bScreen;
struct ARegion;
@@ -67,6 +66,7 @@ void ED_region_header_init(struct ARegion *ar);
void ED_region_header(const struct bContext *C, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
void ED_region_info_draw(struct ARegion *ar, const char *text, int block, float fill_color[4]);
+void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, rctf frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
float ED_region_blend_factor(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
@@ -76,7 +76,6 @@ void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
-
/* areas */
void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
void ED_area_exit(struct bContext *C, struct ScrArea *sa);
@@ -86,6 +85,7 @@ void ED_area_tag_redraw(ScrArea *sa);
void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
void ED_area_tag_refresh(ScrArea *sa);
void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
void ED_area_headerprint(ScrArea *sa, const char *str);
void ED_area_newspace(struct bContext *C, ScrArea *sa, int type);
void ED_area_prevspace(struct bContext *C, ScrArea *sa);
@@ -109,10 +109,11 @@ void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh,
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
-void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
+void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa, const bool was_prev_temp);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
+bool ED_screen_stereo3d_required(struct bScreen *screen);
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index d3b1a824104..6daaac5bb42 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -34,7 +34,6 @@ struct ARegion;
struct bContext;
struct Object;
struct RegionView3D;
-struct Scene;
struct ViewContext;
struct rcti;
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index a3b4981dad8..732e67a341d 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -35,17 +35,14 @@
/* ******************* Registration Function ********************** */
struct ARegion;
-struct EnumPropertyItem;
struct ListBase;
struct Object;
struct View3D;
struct bContext;
-struct uiLayout;
struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperatorType;
-struct wmWindowManager;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
@@ -86,7 +83,8 @@ enum TfmMode {
TFM_ALIGN,
TFM_EDGE_SLIDE,
TFM_VERT_SLIDE,
- TFM_SEQ_SLIDE
+ TFM_SEQ_SLIDE,
+ TFM_BONE_ENVELOPE_DIST,
};
/* TRANSFORM CONTEXTS */
@@ -109,7 +107,6 @@ enum TfmMode {
bool calculateTransformCenter(struct bContext *C, int centerMode, float cent3d[3], float cent2d[2]);
struct TransInfo;
-struct ScrArea;
struct Base;
struct Scene;
struct Object;
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index e26e03473e0..496ce7f2c60 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -31,15 +31,9 @@
#ifndef __ED_UTIL_H__
#define __ED_UTIL_H__
-struct Scene;
-struct Object;
struct bContext;
-struct ARegion;
-struct uiBlock;
struct wmOperator;
struct wmOperatorType;
-struct BMEditMesh;
-struct Mesh;
/* ed_util.c */
@@ -48,6 +42,8 @@ void ED_editors_exit(struct bContext *C);
bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
+void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+
/* ************** Undo ************************ */
/* undo.c */
@@ -66,7 +62,7 @@ int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
-int ED_undo_valid(const struct bContext *C, const char *undoname);
+bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
/* undo_editmode.c */
void undo_editmode_push(struct bContext *C, const char *name,
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 3e8f234e979..535683823bf 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -37,13 +37,11 @@ struct BMFace;
struct BMLoop;
struct Image;
struct ImageUser;
-struct MTFace;
struct MTexPoly;
struct Main;
struct Object;
struct Scene;
struct SpaceImage;
-struct bContext;
struct bNode;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 5fc5738c88f..be4204e7cb7 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -61,6 +61,7 @@ struct rcti;
struct wmOperator;
struct wmOperatorType;
struct wmWindow;
+struct wmWindowManager;
struct GPUFX;
struct GPUOffScreen;
struct GPUFXSettings;
@@ -103,7 +104,7 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
void ED_view3d_depth_update(struct ARegion *ar);
-float ED_view3d_depth_read_cached(struct ViewContext *vc, int x, int y);
+float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
@@ -218,51 +219,62 @@ void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], floa
bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
+void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
/* end */
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2]);
-bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d,
- float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
-bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi,
- struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
+void ED_view3d_dist_range_get(
+ const struct View3D *v3d,
+ float r_dist_range[2]);
+bool ED_view3d_clip_range_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
+bool ED_view3d_viewplane_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
+ struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
-void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- struct rctf *r_viewborder, const bool no_shift);
-void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- float r_size[2]);
+void ED_view3d_calc_camera_border(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ struct rctf *r_viewborder, const bool no_shift);
+void ED_view3d_calc_camera_border_size(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float r_size[2]);
bool ED_view3d_calc_render_border(struct Scene *scene, struct View3D *v3d,
struct ARegion *ar, struct rcti *rect);
void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
-bool ED_view3d_clipping_test(struct RegionView3D *rv3d, const float co[3], const bool is_local);
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local);
void ED_view3d_clipping_set(struct RegionView3D *rv3d);
void ED_view3d_clipping_enable(void);
void ED_view3d_clipping_disable(void);
-float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3]);
+float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius);
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius);
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+float ED_view3d_radius_to_dist(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius);
void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4]);
/* backbuffer select and draw support */
-void view3d_validate_backbuf(struct ViewContext *vc);
-struct ImBuf *view3d_read_backbuf(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
-unsigned int view3d_sample_backbuf_rect(struct ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index));
-unsigned int view3d_sample_backbuf(struct ViewContext *vc, int x, int y);
+void ED_view3d_backbuf_validate(struct ViewContext *vc);
+struct ImBuf *ED_view3d_backbuf_read(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
+unsigned int ED_view3d_backbuf_sample_rect(
+ struct ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist);
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
+unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
/* draws and does a 4x4 sample */
bool ED_view3d_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
@@ -313,12 +325,13 @@ void ED_view3d_draw_offscreen(
struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp,
struct GPUOffScreen *ofs,
- struct GPUFX *fx, struct GPUFXSettings *fx_settings);
+ struct GPUFX *fx, struct GPUFXSettings *fx_settings,
+ const char *viewname);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256]);
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]);
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
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);
@@ -329,15 +342,13 @@ char ED_view3d_lock_view_from_index(int index);
char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
-uint64_t ED_view3d_datamask(struct Scene *scene, struct View3D *v3d);
-uint64_t ED_view3d_screen_datamask(struct bScreen *screen);
+uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
+uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
-bool ED_view3d_view_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
-
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* camera lock functions */
-bool ED_view3d_camera_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* copy the camera to the view before starting a view transformation */
void ED_view3d_camera_lock_init_ex(struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -377,6 +388,10 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx,
#endif
/* render */
+void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
+#define V3D_IS_ZBUF(v3d) \
+ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b1bb48b58ed..b5e1b9f08b1 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -40,14 +40,11 @@
/* Struct Declarations */
struct ID;
-struct Main;
struct ListBase;
struct ARegion;
-struct ARegionType;
struct ScrArea;
struct wmEvent;
struct wmWindow;
-struct wmWindowManager;
struct wmOperator;
struct AutoComplete;
struct bContext;
@@ -58,18 +55,14 @@ struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct rcti;
-struct rctf;
struct uiList;
struct uiStyle;
struct uiFontStyle;
struct uiWidgetColors;
-struct ColorBand;
-struct CurveMapping;
struct Image;
struct ImageUser;
struct wmOperatorType;
struct uiWidgetColors;
-struct Tex;
struct MTex;
struct ImBuf;
struct bNodeTree;
@@ -181,10 +174,11 @@ enum {
UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */
UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */
UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
- UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */
+ UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be gray out */
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
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 */
};
#define UI_PANEL_WIDTH 340
@@ -279,7 +273,6 @@ typedef enum {
UI_BTYPE_WAVEFORM = (49 << 9),
UI_BTYPE_VECTORSCOPE = (50 << 9),
UI_BTYPE_PROGRESS_BAR = (51 << 9),
- UI_BTYPE_SEARCH_MENU_UNLINK = (52 << 9),
UI_BTYPE_NODE_SOCKET = (53 << 9),
UI_BTYPE_SEPR = (54 << 9),
UI_BTYPE_SEPR_LINE = (55 << 9),
@@ -326,6 +319,11 @@ void UI_draw_safe_areas(
#define UI_SCROLL_NO_OUTLINE (1 << 2)
void UI_draw_widget_scroll(struct uiWidgetColors *wcol, const struct rcti *rect, const struct rcti *slider, int state);
+/* Shortening string helper. */
+float UI_text_clip_middle_ex(
+ struct uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep);
+
/* Callbacks
*
* UI_block_func_handle_set/ButmFunc are for handling events through a callback.
@@ -403,7 +401,7 @@ void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *
void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
-void UI_popup_block_close(struct bContext *C, uiBlock *block);
+void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
/* Blocks
*
@@ -490,6 +488,14 @@ bool UI_but_active_only(const struct bContext *C, struct ARegion *ar, uiBlock
void UI_but_execute(const struct bContext *C, uiBut *but);
+bool UI_but_online_manual_id(
+ const uiBut *but,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
+bool UI_but_online_manual_id_from_active(
+ const struct bContext *C,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
/* Buttons
*
@@ -682,6 +688,7 @@ void UI_but_func_drawextra_set(
void *arg1, void *arg2);
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN);
+void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *ar,
const void *rna_poin_data, const char *rna_prop_id);
@@ -739,7 +746,7 @@ void UI_panel_category_draw_all(struct ARegion *ar, const
* as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */
void UI_region_handlers_add(struct ListBase *handlers);
-void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click);
+void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const char flag);
void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
@@ -882,7 +889,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id);
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand);
-void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels);
void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
@@ -894,8 +901,11 @@ void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *prop
PointerRNA *used_ptr, const char *used_propname, int active_layer);
void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_state);
-void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact);
+void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact, int multiview);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
+void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
+void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr);
void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, Image *ima, ImageUser *iuser);
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
@@ -971,13 +981,17 @@ void ED_button_operatortypes(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
+bool UI_context_copy_to_selected_list(
+ struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
+ struct ListBase *r_lb, bool *r_use_path_from_id, char **r_path);
+
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
void UI_context_active_but_prop_handle(struct bContext *C);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
-void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
+void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
/* Styled text draw */
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 74927428363..634dd3d5bbc 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -34,12 +34,6 @@
struct bContext;
struct ID;
-struct Image;
-struct ImBuf;
-struct World;
-struct Tex;
-struct Lamp;
-struct Material;
struct PreviewImage;
struct PointerRNA;
@@ -55,7 +49,7 @@ typedef struct IconFile {
#define ICON_DEFAULT_HEIGHT_SCALE ((int)(UI_UNIT_Y * 0.8f))
#define ICON_DEFAULT_WIDTH_SCALE ((int)(UI_UNIT_X * 0.8f))
-#define PREVIEW_DEFAULT_HEIGHT 96
+#define PREVIEW_DEFAULT_HEIGHT 128
/*
* Resizable Icons for Blender
@@ -70,7 +64,7 @@ void UI_id_icon_render(
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_preview(float x, float y, int icon_id);
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size);
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size);
void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3]);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 4a484212a63..2b19b6180e5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -294,14 +294,16 @@ enum {
TH_INFO_DEBUG_TEXT,
TH_VIEW_OVERLAY,
- TH_V3D_CLIPPING_BORDER
+ TH_V3D_CLIPPING_BORDER,
+
+ TH_METADATA_BG,
+ TH_METADATA_TEXT
};
/* XXX WARNING: previous is saved in file, so do not change order! */
/* specific defines per space should have higher define values */
struct bTheme;
-struct PointerRNA;
struct bThemeState {
struct bTheme *theme;
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 4d7446a7a81..2c8f5f6590a 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -233,7 +233,6 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar,
const struct rctf *cur, const int smooth_viewtx);
-
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#endif /* __UI_VIEW2D_H__ */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index bad09a7c441..e045db8fdd2 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -82,11 +83,11 @@
#define B_NOP -1
-/*
- * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt
+/**
+ * a full doc with API notes can be found in 'blender/doc/guides/interface_API.txt'
*
- * uiBlahBlah() external function
- * ui_blah_blah() internal function
+ * `uiBlahBlah()` external function.
+ * `ui_blah_blah()` internal function.
*/
static void ui_but_free(const bContext *C, uiBut *but);
@@ -513,7 +514,7 @@ static void ui_draw_links(uiBlock *block)
uiBut *but;
uiLinkLine *line;
- /* Draw the grey out lines. Do this first so they appear at the
+ /* Draw the gray out lines. Do this first so they appear at the
* bottom of inactive or active lines.
* As we go, remember if we see any active or selected lines. */
bool found_selectline = false;
@@ -548,7 +549,7 @@ static void ui_draw_links(uiBlock *block)
}
/* Draw any active lines (lines with either button being hovered over).
- * Do this last so they appear on top of inactive and grey out lines. */
+ * Do this last so they appear on top of inactive and gray out lines. */
if (found_activeline) {
for (but = block->buttons.first; but; but = but->next) {
if (but->type == UI_BTYPE_LINK && but->link) {
@@ -1099,13 +1100,16 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
-/* this goes in a seemingly weird pattern:
+/**
+ * This goes in a seemingly weird pattern:
*
+ * <pre>
* 4
* 5 6
* 1 2
* 7 8
* 3
+ * </pre>
*
* but it's actually quite logical. It's designed to be 'upwards compatible'
* for muscle memory so that the menu item locations are fixed and don't move
@@ -1930,7 +1934,7 @@ void ui_but_value_set(uiBut *but, double value)
int ui_but_string_get_max_length(uiBut *but)
{
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
@@ -1951,6 +1955,56 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
return but_iter;
}
+/** \name Check to show extra icons
+ *
+ * Extra icons are shown on the right hand side of buttons.
+ * \{ */
+
+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));
+}
+
+static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+{
+ StructRNA *type;
+ short idcode;
+
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+
+ if (but->rnaprop == NULL) {
+ return false;
+ }
+
+ 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;
+ }
+
+ return UI_BUT_ICONEXTRA_NONE;
+}
+
+/** \} */
+
+
static double ui_get_but_scale_unit(uiBut *but, double value)
{
UnitSettings *unit = but->block->unit;
@@ -2031,7 +2085,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
*/
void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -2073,7 +2127,7 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int
BLI_strncpy(str, but->poin, maxlen);
return;
}
- else if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(str, but->poin, maxlen);
return;
@@ -2194,7 +2248,7 @@ static void ui_but_string_free_internal(uiBut *but)
bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2246,7 +2300,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
return true;
}
- else if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(but->poin, str, but->hardmax);
return true;
@@ -2264,6 +2318,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
double value;
if (ui_but_string_set_eval_num(C, but, str, &value) == false) {
+ WM_report_banner_show(C);
return false;
}
@@ -2714,11 +2769,11 @@ void ui_but_update(uiBut *but)
}
else {
const int prec = ui_but_calc_float_precision(but, value);
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
}
}
else {
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
}
if (but->rnaprop) {
@@ -2754,7 +2809,6 @@ void ui_but_update(uiBut *but)
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
- case UI_BTYPE_SEARCH_MENU_UNLINK:
if (!but->editstr) {
char str[UI_MAX_DRAW_STR];
@@ -3047,17 +3101,18 @@ void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3])
/**
* \brief ui_def_but is the function that draws many button types
*
- * \param x,y The lower left hand corner of the button (X axis)
- * \param width,height The size of the button.
+ * \param x, y: The lower left hand corner of the button (X axis)
+ * \param width, height: The size of the button.
*
* for float buttons:
- * - \a a1 Click Step (how much to change the value each click)
- * - \a a2 Number of decimal point values to display. 0 defaults to 3 (0.000)
- * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
+ * \param a1: Click Step (how much to change the value each click)
+ * \param a2: Number of decimal point values to display. 0 defaults to 3 (0.000)
+ * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
*/
-static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- void *poin, float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ void *poin, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but;
int slen;
@@ -3139,7 +3194,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
ELEM(but->type,
UI_BTYPE_MENU, UI_BTYPE_TEXT, UI_BTYPE_LABEL,
UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_PROGRESS_BAR, UI_BTYPE_SEARCH_MENU_UNLINK))
+ UI_BTYPE_PROGRESS_BAR))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3186,6 +3241,19 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
return but;
}
+void ui_def_but_icon(uiBut *but, const int icon, const int flag)
+{
+ if (icon) {
+ ui_icon_ensure_deferred(but->block->evil_C, icon, (flag & UI_BUT_ICON_PREVIEW) != 0);
+ }
+ but->icon = (BIFIconID)icon;
+ but->flag |= flag;
+
+ if (but->str && but->str[0]) {
+ but->drawflag |= UI_BUT_ICON_LEFT;
+ }
+}
+
static void ui_def_but_rna__disable(uiBut *but)
{
but->flag |= UI_BUT_DISABLED;
@@ -3325,10 +3393,11 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
* When this kind of change won't disrupt branches, best look into making more
* of our UI functions take prop rather then propname.
*/
-static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- PointerRNA *ptr, PropertyRNA *prop, int index,
- float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but_rna(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ PointerRNA *ptr, PropertyRNA *prop, int index,
+ float min, float max, float a1, float a2, const char *tip)
{
const PropertyType proptype = RNA_property_type(prop);
uiBut *but;
@@ -3448,11 +3517,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
but->rnaindex = 0;
if (icon) {
- but->icon = (BIFIconID)icon;
- but->flag |= UI_HAS_ICON;
- if (str[0]) {
- but->drawflag |= UI_BUT_ICON_LEFT;
- }
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) {
@@ -3639,8 +3704,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
static void ui_but_update_and_icon_set(uiBut *but, int icon)
{
if (icon) {
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
ui_but_update(but);
@@ -4014,7 +4078,7 @@ void UI_but_drag_set_value(uiBut *but)
void UI_but_drag_set_image(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale)
{
but->dragtype = WM_DRAG_PATH;
- but->icon = icon; /* no flag UI_HAS_ICON, so icon doesnt draw in button */
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesnt draw in button */
but->dragpoin = (void *)path;
but->imb = imb;
but->imb_scale = scale;
@@ -4168,8 +4232,7 @@ uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, in
{
uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag |= UI_BUT_ICON_LEFT;
but->flag |= UI_BUT_ICON_SUBMENU;
@@ -4184,8 +4247,7 @@ uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int ic
{
uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag &= ~UI_BUT_ICON_LEFT;
but->menu_create_func = func;
@@ -4201,7 +4263,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
/* XXX temp, old menu calls pass on icon arrow, which is now UI_BUT_ICON_SUBMENU flag */
if (icon != ICON_RIGHTARROW_THIN) {
- but->icon = (BIFIconID) icon;
+ ui_def_but_icon(but, icon, 0);
but->drawflag |= UI_BUT_ICON_LEFT;
}
but->flag |= UI_HAS_ICON;
@@ -4218,9 +4280,8 @@ uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int
{
uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, retval, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
-
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT;
but->block_create_func = func;
@@ -4253,9 +4314,8 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
{
uiBut *but = ui_def_but(block, UI_BTYPE_SEARCH_MENU, retval, "", x, y, width, height, arg, 0.0, maxlen, a1, a2, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
-
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
ui_but_update(but);
@@ -4264,8 +4324,11 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
}
-/* arg is user value, searchfunc and handlefunc both get it as arg */
-/* if active set, button opens with this item visible and selected */
+/**
+ * \param sfunc, bfunc: both get it as \a arg.
+ * \param arg: user value,
+ * \param active: when set, button opens with this item visible and selected.
+ */
void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active)
{
but->search_func = sfunc;
@@ -4334,11 +4397,14 @@ static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *a
}
}
-/* Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
- * to call again the right op with the right options (properties values). */
-uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *properties,
- void *arg, int retval, int icon, int maxlen, int x, int y,
- short width, short height, float a1, float a2, const char *tip)
+/**
+ * Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
+ * to call again the right op with the right options (properties values).
+ */
+uiBut *uiDefSearchButO_ptr(
+ uiBlock *block, wmOperatorType *ot, IDProperty *properties,
+ void *arg, int retval, int icon, int maxlen, int x, int y,
+ short width, short height, float a1, float a2, const char *tip)
{
uiBut *but;
@@ -4357,7 +4423,8 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *prope
return but;
}
-/* push a new event onto event queue to activate the given button
+/**
+ * push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
*/
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
@@ -4390,7 +4457,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
if (type == BUT_GET_LABEL) {
if (but->str) {
- tmp = BLI_strdup(but->str);
+ const char *str_sep;
+ size_t str_len;
+
+ if ((but->flag & UI_BUT_HAS_SEP_CHAR) &&
+ (str_sep = strrchr(but->str, UI_SEP_CHAR)))
+ {
+ str_len = (str_sep - but->str);
+ }
+ else {
+ str_len = strlen(but->str);
+ }
+
+ tmp = BLI_strdupn(but->str, str_len);
}
else {
type = BUT_GET_RNA_LABEL; /* Fail-safe solution... */
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 24a30ebe3d8..f6757b35462 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -54,13 +54,13 @@
#include "interface_intern.h"
-static FCurve *ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven)
+static FCurve *ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
{
/* for entire array buttons we check the first component, it's not perfect
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven);
+ return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
}
void ui_but_anim_flag(uiBut *but, float cfra)
@@ -69,11 +69,16 @@ void ui_but_anim_flag(uiBut *but, float cfra)
bAction *act;
FCurve *fcu;
bool driven;
-
+ bool special;
+
but->flag &= ~(UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN);
-
- fcu = ui_but_get_fcurve(but, &adt, &act, &driven);
-
+
+ /* NOTE: "special" is reserved for special F-Curves stored on the animation data
+ * itself (which are used to animate properties of the animation data).
+ * We count those as "animated" too for now
+ */
+ fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
+
if (fcu) {
if (!driven) {
but->flag |= UI_BUT_ANIMATED;
@@ -98,10 +103,10 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
-
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven);
-
+ bool driven, special;
+
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
+
if (fcu && driven) {
driver = fcu->driver;
@@ -118,9 +123,9 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
+ bool driven, special;
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven);
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
if (fcu && driven) {
driver = fcu->driver;
@@ -215,8 +220,9 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
bAction *action;
FCurve *fcu;
bool driven;
+ bool special;
- fcu = ui_but_get_fcurve(but, NULL, &action, &driven);
+ fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special);
if (fcu && !driven) {
id = but->rnapoin.id.data;
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 07d580b9138..2c13b199bba 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -508,8 +508,9 @@ static void draw_scope_end(const rctf *rect, GLint *scissor)
UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f);
}
-static void histogram_draw_one(float r, float g, float b, float alpha,
- float x, float y, float w, float h, const float *data, int res, const bool is_line)
+static void histogram_draw_one(
+ float r, float g, float b, float alpha,
+ float x, float y, float w, float h, const float *data, int res, const bool is_line)
{
int i;
@@ -1260,8 +1261,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
size = BLI_rcti_size_x(rect) / 200.f;
else
size = BLI_rcti_size_y(rect) / 200.f;
-
- glScalef(size, size, size);
+
+ glScalef(size, size, MIN2(size, 1.0f));
if (displist == 0) {
GLUquadricObj *qobj;
@@ -1453,7 +1454,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
glEnd();
}
else if (cumap->cur == 3) {
- float lum = rgb_to_bw(cumap->sample);
+ float lum = IMB_colormanagement_get_luminance(cumap->sample);
glColor3ub(240, 240, 240);
glBegin(GL_LINES);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index aabb8e29fa9..97aa865c287 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -36,6 +36,8 @@
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
@@ -176,8 +178,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
if (sa) {
if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceImage *sima = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -188,8 +190,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
}
}
else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceNode *snode = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -200,8 +202,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
}
}
else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceClip *sc = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -379,12 +381,11 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-/* Data Dropper
- *
- * note: datadropper is only internal name to avoid confusion in this file
- */
+/* Data Dropper */
/** \name Eyedropper (ID data-blocks)
+ *
+ * \note: datadropper is only internal name to avoid confusion in this file.
* \{ */
typedef struct DataDropper {
@@ -436,7 +437,8 @@ static int datadropper_init(bContext *C, wmOperator *op)
type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
ddr->idcode = RNA_type_to_ID_code(type);
BLI_assert(ddr->idcode != 0);
- ddr->idcode_name = BKE_idcode_to_name(ddr->idcode);
+ /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
+ ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
return true;
}
@@ -456,6 +458,8 @@ static void datadropper_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
+
+ WM_event_add_mousemove(C);
}
static void datadropper_cancel(bContext *C, wmOperator *op)
@@ -482,8 +486,8 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
if (sa) {
if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
const int mval[2] = {
mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -632,7 +636,7 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper Datablock";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a datablock from the Blender Window to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -651,12 +655,11 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-/* Depth Dropper
- *
- * note: depthdropper is only internal name to avoid confusion in this file
- */
+/* Depth Dropper */
/** \name Eyedropper (Depth)
+ *
+ * \note: depthdropper is only internal name to avoid confusion in this file.
* \{ */
typedef struct DepthDropper {
@@ -765,8 +768,8 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
if (sa) {
if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
/* weak, we could pass in some reference point */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a6ff5bb3ad3..58cf6b900b9 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -52,9 +52,9 @@
#include "BLI_linklist.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_cursor_utf8.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
-#include "BLI_string_cursor_utf8.h"
#include "BLF_translation.h"
@@ -99,6 +99,9 @@
/* support dragging multiple number buttons at once */
#define USE_DRAG_MULTINUM
+/* allow dragging/editing all other selected items at once */
+#define USE_ALLSELECT
+
/* so we can avoid very small mouse-moves from jumping away from keyboard navigation [#34936] */
#define USE_KEYNAV_LIMIT
@@ -158,17 +161,63 @@ typedef enum uiHandleButtonState {
} uiHandleButtonState;
+#ifdef USE_ALLSELECT
+
+/* Unfortunately theres no good way handle more generally:
+ * (propagate single clicks on layer buttons to other objects) */
+#define USE_ALLSELECT_LAYER_HACK
+
+typedef struct uiSelectContextElem {
+ PointerRNA ptr;
+ union {
+ bool val_b;
+ int val_i;
+ float val_f;
+ };
+} uiSelectContextElem;
+
+typedef struct uiSelectContextStore {
+ uiSelectContextElem *elems;
+ int elems_len;
+ bool do_free;
+ bool is_enabled;
+ /* When set, simply copy values (don't apply difference).
+ * Rules are:
+ * - dragging numbers uses delta.
+ * - typing in values will assign to all. */
+ bool is_copy;
+} uiSelectContextStore;
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data);
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data);
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data,
+ const double value, const double value_orig);
+
+#define IS_ALLSELECT_EVENT(event) ((event)->alt != 0)
+
+/** just show a tinted color so users know its activated */
+#define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE
+
+#endif /* USE_ALLSELECT */
+
+
#ifdef USE_DRAG_MULTINUM
-/* how far to drag before we check for gesture direction (in pixels),
+/**
+ * how far to drag before we check for gesture direction (in pixels),
* note: half the height of a button is about right... */
#define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4)
-/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
+/**
+ * how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
* locking down the buttons so we can drag freely without worrying about vertical movement. */
#define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4)
-/* how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
+/**
+ * how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
* note: we should be quite strict here, since doing a vertical gesture by accident should be avoided,
* however with some care a user should be able to do a vertical movement without *missing*. */
#define DRAG_MULTINUM_THRESHOLD_VERTICAL (0.75f)
@@ -178,6 +227,10 @@ typedef enum uiHandleButtonState {
typedef struct uiButMultiState {
double origvalue;
uiBut *but;
+
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
} uiButMultiState;
typedef struct uiHandleButtonMulti {
@@ -210,8 +263,6 @@ typedef struct uiHandleButtonMulti {
#endif /* USE_DRAG_MULTINUM */
-
-
typedef struct uiHandleButtonData {
wmWindowManager *wm;
wmWindow *window;
@@ -280,6 +331,10 @@ typedef struct uiHandleButtonData {
uiHandleButtonMulti multi_data;
#endif
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
+
/* post activate */
uiButtonActivateType posttype;
uiBut *postbut;
@@ -328,14 +383,14 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event);
static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree);
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree);
static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *userdata);
static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
-static void button_timers_tooltip_remove(bContext *C, uiBut *but);
#ifdef USE_DRAG_MULTINUM
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block);
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block);
static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut *but);
#endif
@@ -366,7 +421,7 @@ static void ui_color_snap_hue(const enum eSnapType snap, float *r_hue)
{
const float snap_increment = (snap == SNAP_ON_SMALL) ? 24 : 12;
BLI_assert(snap != SNAP_OFF);
- *r_hue = floorf(0.5f + ((*r_hue) * snap_increment)) / snap_increment;
+ *r_hue = roundf((*r_hue) * snap_increment) / snap_increment;
}
/* assumes event type is MOUSEPAN */
@@ -413,7 +468,7 @@ bool ui_but_is_editable_as_text(const uiBut *but)
{
return ELEM(but->type,
UI_BTYPE_TEXT, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER,
- UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK);
+ UI_BTYPE_SEARCH_MENU);
}
@@ -478,10 +533,9 @@ static float ui_mouse_scale_warp_factor(const bool shift)
return shift ? 0.05f : 1.0f;
}
-static void ui_mouse_scale_warp(uiHandleButtonData *data,
- const float mx, const float my,
- float *r_mx, float *r_my,
- const bool shift)
+static void ui_mouse_scale_warp(
+ uiHandleButtonData *data, const float mx, const float my,
+ float *r_mx, float *r_my, const bool shift)
{
const float fac = ui_mouse_scale_warp_factor(shift);
@@ -894,7 +948,7 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
return NULL;
}
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block)
{
uiBut *but;
@@ -903,6 +957,16 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
uiButMultiState *mbut_state = ui_multibut_lookup(data, but);
if (mbut_state) {
ui_but_value_set(but, mbut_state->origvalue);
+
+#ifdef USE_ALLSELECT
+ if (mbut_state->select_others.elems_len > 0) {
+ ui_selectcontext_apply(
+ C, but, &mbut_state->select_others,
+ mbut_state->origvalue, mbut_state->origvalue);
+ }
+#else
+ UNUSED_VARS(C);
+#endif
}
}
}
@@ -910,7 +974,26 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
{
+#ifdef USE_ALLSELECT
+ if (data->multi_data.mbuts) {
+ LinkNode *list = data->multi_data.mbuts;
+ while (list) {
+ LinkNode *next = list->next;
+ uiButMultiState *mbut_state = list->link;
+
+ if (mbut_state->select_others.elems) {
+ MEM_freeN(mbut_state->select_others.elems);
+ }
+
+ MEM_freeN(list->link);
+ MEM_freeN(list);
+ list = next;
+ }
+ }
+#else
BLI_linklist_freeN(data->multi_data.mbuts);
+#endif
+
data->multi_data.mbuts = NULL;
if (data->multi_data.bs_mbuts) {
@@ -979,6 +1062,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
uiBut *but;
BLI_assert(data->multi_data.init == BUTTON_MULTI_INIT_SETUP);
+ BLI_assert(data->multi_data.has_mbuts);
data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
@@ -1016,6 +1100,24 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
void *active_back;
ui_but_execute_begin(C, ar, but, &active_back);
+
+#ifdef USE_ALLSELECT
+ if (data->select_others.is_enabled) {
+ /* init once! */
+ if (mbut_state->select_others.elems_len == 0) {
+ ui_selectcontext_begin(C, but, &mbut_state->select_others);
+ }
+ if (mbut_state->select_others.elems_len == 0) {
+ mbut_state->select_others.elems_len = -1;
+ }
+ }
+
+ /* needed so we apply the right deltas */
+ but->active->origvalue = mbut_state->origvalue;
+ but->active->select_others = mbut_state->select_others;
+ but->active->select_others.do_free = false;
+#endif
+
BLI_assert(active_back == NULL);
/* no need to check 'data->state' here */
if (data->str) {
@@ -1064,8 +1166,9 @@ typedef struct uiDragToggleHandle {
int xy_last[2];
} uiDragToggleHandle;
-static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy_src[2], const int xy_dst[2])
+static bool ui_drag_toggle_set_xy_xy(
+ bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ const int xy_src[2], const int xy_dst[2])
{
/* popups such as layers won't re-evaluate on redraw */
const bool do_check = (ar->regiontype == RGN_TYPE_TEMPORARY);
@@ -1225,6 +1328,267 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
#endif /* USE_DRAG_TOGGLE */
+#ifdef USE_ALLSELECT
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
+{
+ PointerRNA ptr, lptr, idptr;
+ PropertyRNA *prop, *lprop;
+ bool success = false;
+ int index;
+
+ char *path = NULL;
+ ListBase lb = {NULL};
+
+ ptr = but->rnapoin;
+ prop = but->rnaprop;
+ index = but->rnaindex;
+
+ /* for now don't support whole colors */
+ if (index == -1)
+ return false;
+
+ /* if there is a valid property that is editable... */
+ if (ptr.data && prop) {
+ CollectionPointerLink *link;
+ bool use_path_from_id;
+ int i;
+
+ /* some facts we want to know */
+ 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__);
+
+ 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 */
+#if 0
+ 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 */
+#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);
+ }
+#endif
+ }
+
+ continue;
+ }
+ }
+
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ }
+ }
+
+ success = (selctx_data->elems_len != 0);
+
+finally:
+ if (selctx_data->elems_len == 0) {
+ MEM_SAFE_FREE(selctx_data->elems);
+ }
+
+ MEM_SAFE_FREE(path);
+ BLI_freelistN(&lb);
+
+ /* caller can clear */
+ selctx_data->do_free = true;
+
+ if (success) {
+ but->flag |= UI_BUT_IS_SELECT_CONTEXT;
+ }
+
+ return success;
+}
+
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data)
+{
+ if (selctx_data->do_free) {
+ if (selctx_data->elems) {
+ MEM_freeN(selctx_data->elems);
+ }
+ }
+
+ but->flag &= ~UI_BUT_IS_SELECT_CONTEXT;
+}
+
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data,
+ const double value, const double value_orig)
+{
+ if (selctx_data->elems) {
+ PropertyRNA *prop = but->rnaprop;
+ PropertyRNA *lprop = but->rnaprop;
+ int index = but->rnaindex;
+ int i;
+ const bool use_delta = (selctx_data->is_copy == false);
+
+ union {
+ bool b;
+ int i;
+ float f;
+ } delta, min, max;
+
+ const bool is_array = RNA_property_array_check(prop);
+ const int rna_type = RNA_property_type(prop);
+
+ if (rna_type == PROP_FLOAT) {
+ delta.f = use_delta ? (value - value_orig) : value;
+ RNA_property_float_range(&but->rnapoin, prop, &min.f, &max.f);
+ }
+ else if (rna_type == PROP_INT) {
+ delta.i = use_delta ? ((int)value - (int)value_orig) : (int)value;
+ RNA_property_int_range(&but->rnapoin, prop, &min.i, &max.i);
+ }
+ else if (rna_type == PROP_ENUM) {
+ delta.i = RNA_property_enum_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ if (is_array) {
+ delta.b = RNA_property_boolean_get_index(&but->rnapoin, prop, index); /* not a delta infact */
+ }
+ else {
+ delta.b = RNA_property_boolean_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ }
+
+#ifdef USE_ALLSELECT_LAYER_HACK
+ /* make up for not having 'handle_layer_buttons' */
+ {
+ PropertySubType subtype = RNA_property_subtype(prop);
+
+ if ((rna_type == PROP_BOOLEAN) &&
+ ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER) &&
+ is_array &&
+ /* could check for 'handle_layer_buttons' */
+ but->func)
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (!win->eventstate->shift) {
+ const int len = RNA_property_array_length(&but->rnapoin, prop);
+ int *tmparray = MEM_callocN(sizeof(int) * len, __func__);
+
+ tmparray[index] = true;
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+ RNA_property_boolean_set_array(&lptr, lprop, tmparray);
+ RNA_property_update(C, &lptr, lprop);
+ }
+
+ MEM_freeN(tmparray);
+
+ return;
+ }
+ }
+ }
+#endif
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+
+ if (rna_type == PROP_FLOAT) {
+ float other_value = use_delta ? (other->val_f + delta.f) : delta.f;
+ CLAMP(other_value, min.f, max.f);
+ if (is_array) {
+ RNA_property_float_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_float_set(&lptr, lprop, other_value);
+ }
+ }
+ else if (rna_type == PROP_INT) {
+ int other_value = use_delta ? (other->val_i + delta.i) : delta.i;
+ CLAMP(other_value, min.i, max.i);
+ if (is_array) {
+ RNA_property_int_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_int_set(&lptr, lprop, other_value);
+ }
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ const bool other_value = delta.b;
+ if (is_array) {
+ RNA_property_boolean_set_index(&lptr, lprop, index, other_value);
+ }
+ else {
+ RNA_property_boolean_set(&lptr, lprop, delta.b);
+ }
+ }
+ else if (rna_type == PROP_ENUM) {
+ const int other_value = delta.i;
+ BLI_assert(!is_array);
+ RNA_property_enum_set(&lptr, lprop, other_value);
+ }
+
+ RNA_property_update(C, &lptr, prop);
+ }
+ }
+}
+
+#endif /* USE_ALLSELECT */
+
+
static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{
rcti rect;
@@ -1278,10 +1642,11 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data,
ar_prev = CTX_wm_region(C);
CTX_wm_region_set(C, data->region);
- WM_event_add_ui_handler(C, &data->window->modalhandlers,
- ui_handler_region_drag_toggle,
- ui_handler_region_drag_toggle_remove,
- drag_info, false);
+ WM_event_add_ui_handler(
+ C, &data->window->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info, WM_HANDLER_BLOCKING);
CTX_wm_region_set(C, ar_prev);
}
@@ -1596,9 +1961,8 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
data->str = data->origstr;
data->origstr = NULL;
data->value = data->origvalue;
- data->origvalue = 0.0;
copy_v3_v3(data->vec, data->origvec);
- data->origvec[0] = data->origvec[1] = data->origvec[2] = 0.0f;
+ /* postpone clearing origdata */
}
else {
/* we avoid applying interactive edits a second time
@@ -1609,6 +1973,27 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else if (data->applied_interactive) {
return;
}
+
+#ifdef USE_ALLSELECT
+# ifdef USE_DRAG_MULTINUM
+ if (but->flag & UI_BUT_DRAG_MULTI) {
+ /* pass */
+ }
+ else
+# endif
+ if (data->select_others.elems_len == 0) {
+ wmWindow *win = CTX_wm_window(C);
+ /* may have been enabled before activating */
+ if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) {
+ ui_selectcontext_begin(C, but, &data->select_others);
+ data->select_others.is_enabled = true;
+ }
+ }
+ if (data->select_others.elems_len == 0) {
+ /* dont check again */
+ data->select_others.elems_len = -1;
+ }
+#endif
}
/* ensures we are writing actual values */
@@ -1629,7 +2014,6 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
ui_apply_but_BUT(C, but, data);
break;
case UI_BTYPE_TEXT:
- case UI_BTYPE_SEARCH_MENU_UNLINK:
case UI_BTYPE_SEARCH_MENU:
ui_apply_but_TEX(C, but, data);
break;
@@ -1705,7 +2089,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
if (data->multi_data.has_mbuts) {
if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) {
if (data->cancel) {
- ui_multibut_restore(data, block);
+ ui_multibut_restore(C, data, block);
}
else {
ui_multibut_states_apply(C, data, block);
@@ -1714,6 +2098,15 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
#endif
+#ifdef USE_ALLSELECT
+ ui_selectcontext_apply(C, but, &data->select_others, data->value, data->origvalue);
+#endif
+
+ if (data->cancel) {
+ data->origvalue = 0.0;
+ zero_v3(data->origvec);
+ }
+
but->editstr = editstr;
but->editval = editval;
but->editvec = editvec;
@@ -1732,13 +2125,13 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
for (wmd = drags->first; wmd; wmd = wmd->next) {
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
BLI_strncpy(data->str, id->name + 2, data->maxlen);
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
}
@@ -1879,7 +2272,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1899,7 +2292,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else
BLI_strncpy(active_data->str, buf_paste, active_data->maxlen);
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
/* else uiSearchboxData.active member is not updated [#26856] */
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
@@ -1974,15 +2367,17 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
-/* ************************ password text ******************************
+/**
+ * Password Text
+ * =============
*
* Functions to convert password strings that should not be displayed
- * to asterisk representation (e.g. mysecretpasswd -> *************)
+ * to asterisk representation (e.g. 'mysecretpasswd' -> '*************')
*
* It converts every UTF-8 character to an asterisk, and also remaps
* the cursor position and selection start/end.
*
- * Note: remaping is used, because password could contain UTF-8 characters.
+ * \note: remaping is used, because password could contain UTF-8 characters.
*
*/
@@ -2092,7 +2487,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2182,11 +2577,13 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data,
ui_but_update(but);
}
-/* this is used for both utf8 and ascii, its meant to be used for single keys,
+/**
+ * This is used for both utf8 and ascii, its meant to be used for single keys,
* notice the buffer is either copied or not, so its not suitable for pasting in
* - campbell */
-static bool ui_textedit_type_buf(uiBut *but, uiHandleButtonData *data,
- const char *utf8_buf, int utf8_buf_len)
+static bool ui_textedit_type_buf(
+ uiBut *but, uiHandleButtonData *data,
+ const char *utf8_buf, int utf8_buf_len)
{
char *str;
int len;
@@ -2230,8 +2627,9 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as
return ui_textedit_type_buf(but, data, buf, 1);
}
-static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
- const bool select, strCursorJumpType jump)
+static void ui_textedit_move(
+ uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
+ const bool select, strCursorJumpType jump)
{
const char *str = data->str;
const int len = strlen(str);
@@ -2447,6 +2845,18 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
}
#ifdef WITH_INPUT_IME
+/* test if the translation context allows IME input - used to
+ * avoid weird character drawing if IME inputs non-ascii chars */
+static bool ui_ime_is_lang_supported(void)
+{
+ const char *uilng = BLF_lang_get();
+ const bool is_lang_supported = STREQ(uilng, "zh_CN") ||
+ STREQ(uilng, "zh_TW") ||
+ STREQ(uilng, "ja_JP");
+
+ return ((U.transopts & USER_DOTRANSLATE) && is_lang_supported);
+}
+
/* enable ime, and set up uibut ime data */
static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
{
@@ -2477,8 +2887,7 @@ void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete)
wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete);
}
-/* should be ui_but_ime_data_get */
-wmIMEData *ui_but_get_ime_data(uiBut *but)
+wmIMEData *ui_but_ime_data_get(uiBut *but)
{
if (but->active && but->active->window) {
return but->active->window->ime_data;
@@ -2512,6 +2921,16 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
}
#endif
+#ifdef USE_ALLSELECT
+ if (is_num_but) {
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ data->select_others.is_copy = true;
+
+ }
+ }
+#endif
+
/* retrieve string */
data->maxlen = ui_but_string_get_max_length(but);
data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
@@ -2539,7 +2958,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->selend = len;
/* optional searchbox */
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
data->searchbox = ui_searchbox_create(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -2552,7 +2971,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
#ifdef WITH_INPUT_IME
- if (is_num_but == false) {
+ if (is_num_but == false && ui_ime_is_lang_supported()) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -2789,6 +3208,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELDOWNMOUSE) {
+ break;
+ }
/* fall-through */
case ENDKEY:
ui_textedit_move(but, data, STRCUR_DIR_NEXT,
@@ -2804,6 +3226,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELUPMOUSE) {
+ break;
+ }
/* fall-through */
case HOMEKEY:
ui_textedit_move(but, data, STRCUR_DIR_PREV,
@@ -2854,8 +3279,6 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (autocomplete == AUTOCOMPLETE_FULL_MATCH)
button_activate_state(C, but, BUTTON_STATE_EXIT);
-
- update = true; /* do live update for tab key */
}
/* the hotkey here is not well defined, was G.qual so we check all */
else if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
@@ -2934,7 +3357,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
#endif
if (changed) {
- /* only update when typing for TAB key */
+ /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
if (update && data->interactive) {
ui_apply_but(C, block, but, data, true);
}
@@ -3092,6 +3515,15 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
data->menu->popup = but->block->handle->popup;
}
+#ifdef USE_ALLSELECT
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ }
+ }
+#endif
+
/* this makes adjacent blocks auto open from now on */
//if (but->block->auto_open == 0) but->block->auto_open = 1;
}
@@ -3121,9 +3553,13 @@ int ui_but_menu_direction(uiBut *but)
return 0;
}
-/* Hack for uiList UI_BTYPE_LISTROW buttons to "give" events to overlaying UI_BTYPE_TEXT buttons (cltr-clic rename feature & co). */
-static uiBut *ui_but_list_row_text_activate(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
- uiButtonActivateType activate_type)
+/**
+ * Hack for #uiList #UI_BTYPE_LISTROW buttons to "give" events to overlaying #UI_BTYPE_TEXT buttons
+ * (Ctrl-Click rename feature & co).
+ */
+static uiBut *ui_but_list_row_text_activate(
+ bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
+ uiButtonActivateType activate_type)
{
ARegion *ar = CTX_wm_region(C);
uiBut *labelbut = ui_but_find_mouse_over_ex(ar, event->x, event->y, true);
@@ -3293,9 +3729,11 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+ uiButExtraIconType extra_icon_type;
+
/* unlink icon is on right */
- if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
- ui_but_is_search_unlink_visible(but))
+ if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
{
ARegion *ar = data->region;
rcti rect;
@@ -3306,14 +3744,29 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
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)) {
- /* 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;
+ /* 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);
+ 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);
+ }
+ }
return WM_UI_HANDLER_BREAK;
}
@@ -3352,7 +3805,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
/* Support alt+wheel on expanded enum rows */
if (but->type == UI_BTYPE_ROW) {
const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
@@ -3448,8 +3901,9 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
/* var names match ui_numedit_but_NUM */
-static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, float softmax, float softrange,
- const enum eSnapType snap)
+static float ui_numedit_apply_snapf(
+ uiBut *but, float tempf, float softmin, float softmax, float softrange,
+ const enum eSnapType snap)
{
if (tempf == softmin || tempf == softmax || snap == SNAP_OFF) {
/* pass */
@@ -3477,15 +3931,25 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
softrange /= fac;
}
+ /* workaround, too high snapping values */
+ /* snapping by 10's for float buttons is quite annoying (location, scale...),
+ * but allow for rotations */
+ if ((softrange > 2100.0f)) {
+ int unit_type = UI_but_unit_type_get(but);
+ if (!ELEM(unit_type, PROP_UNIT_ROTATION)) {
+ softrange = 20.0f;
+ }
+ }
+
if (snap == SNAP_ON) {
- if (softrange < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softrange < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
else if (snap == SNAP_ON_SMALL) {
- if (softrange < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softrange < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floor(tempf);
+ if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
BLI_assert(0);
@@ -3498,8 +3962,9 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
return tempf;
}
-static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
- const enum eSnapType snap)
+static float ui_numedit_apply_snap(
+ int temp, float softmin, float softmax,
+ const enum eSnapType snap)
{
if (temp == softmin || temp == softmax)
return temp;
@@ -3518,9 +3983,10 @@ static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
return temp;
}
-static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
- int mx,
- const enum eSnapType snap, float fac)
+static bool ui_numedit_but_NUM(
+ uiBut *but, uiHandleButtonData *data,
+ int mx,
+ const enum eSnapType snap, float fac)
{
float deler, tempf, softmin, softmax, softrange;
int lvalue, temp;
@@ -3636,7 +4102,7 @@ static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
if (!is_float) {
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
temp = ui_numedit_apply_snap(temp, softmin, softmax, snap);
@@ -3689,11 +4155,11 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 1;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 1;
}
@@ -3759,7 +4225,6 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
fac = 1.0f;
if (event->shift) fac /= 10.0f;
- if (event->alt) fac /= 20.0f;
if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac))
ui_numedit_apply(C, block, but, data);
@@ -3854,9 +4319,10 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return retval;
}
-static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
- int mx, const bool is_horizontal,
- const bool snap, const bool shift)
+static bool ui_numedit_but_SLI(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, const bool is_horizontal,
+ const bool snap, const bool shift)
{
float deler, f, tempf, softmin, softmax, softrange;
int temp, lvalue;
@@ -3909,7 +4375,7 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
tempf = softmin + f * softrange;
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
if (snap) {
if (tempf == softmin || tempf == softmax) {
@@ -3919,14 +4385,14 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
if (shift) {
if (tempf == softmin || tempf == softmax) {}
- else if (softmax - softmin < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floorf(tempf);
+ else if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
- if (softmax - softmin < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
}
else {
@@ -3936,7 +4402,7 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
}
if (!ui_but_is_float(but)) {
- lvalue = floor(data->value + 0.5);
+ lvalue = round(data->value);
CLAMP(temp, softmin, softmax);
@@ -3978,11 +4444,11 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 2;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 2;
}
@@ -3991,6 +4457,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
+#ifndef USE_ALLSELECT
/* alt-click on sides to get "arrows" like in UI_BTYPE_NUM buttons, and match wheel usage above */
else if (event->type == LEFTMOUSE && event->alt) {
int halfpos = BLI_rctf_cent_x(&but->rect);
@@ -4000,6 +4467,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else
mx = but->rect.xmax;
}
+#endif
else if (event->type == LEFTMOUSE) {
data->dragstartx = mx;
data->draglastx = mx;
@@ -4286,7 +4754,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_BREAK;
}
else if (but->type == UI_BTYPE_MENU) {
- if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
data->value = ui_but_menu_step(but, direction);
@@ -4342,9 +4810,10 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_UNITVEC(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap)
+static bool ui_numedit_but_UNITVEC(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap)
{
float dx, dy, rad, radsq, mrad, *fp;
int mdx, mdy;
@@ -4410,7 +4879,7 @@ static bool ui_numedit_but_UNITVEC(uiBut *but, uiHandleButtonData *data,
* do this in "angle" space - this gives increments of same size */
for (i = 0; i < 3; i++) {
angle = asinf(fp[i]);
- angle_snap = floorf(0.5f + (angle / snap_steps_angle)) * snap_steps_angle;
+ angle_snap = roundf((angle / snap_steps_angle)) * snap_steps_angle;
fp[i] = sinf(angle_snap);
}
normalize_v3(fp);
@@ -4460,7 +4929,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
ColorPicker *cpicker = but->custom_data;
float hsv_static[3] = {0.0f};
float *hsv = cpicker ? cpicker->color_data : hsv_static;
@@ -4494,6 +4963,12 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
BKE_palette_color_remove(palette, color);
button_activate_state(C, but, BUTTON_STATE_EXIT);
+
+ /* this is risky. it works OK for now,
+ * but if it gives trouble we should delay execution */
+ but->rnapoin = PointerRNA_NULL;
+ but->rnaprop = NULL;
+
return WM_UI_HANDLER_BREAK;
}
}
@@ -4638,9 +5113,10 @@ static void ui_color_picker_to_rgb_HSVCUBE_v(uiBut *but, const float hsv[3], flo
hsv_to_rgb_v(hsv, rgb);
}
-static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -4699,8 +5175,8 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] = x;
- hsv[1] = y;
+ hsv[1] = x;
+ hsv[2] = y;
break;
case UI_GRAD_HV:
hsv[0] = x;
@@ -4757,9 +5233,10 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -4777,8 +5254,8 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] += ndof->rvec[2] * sensitivity;
- hsv[1] += ndof->rvec[0] * sensitivity;
+ hsv[1] += ndof->rvec[2] * sensitivity;
+ hsv[2] += ndof->rvec[0] * sensitivity;
break;
case UI_GRAD_HV:
hsv[0] += ndof->rvec[2] * sensitivity;
@@ -4922,9 +5399,10 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- float mx, float my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ float mx, float my,
+ const enum eSnapType snap, const bool shift)
{
rcti rect;
bool changed = true;
@@ -5019,9 +5497,10 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -5280,7 +5759,8 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData *data,
+static bool ui_numedit_but_CURVE(
+ uiBlock *block, uiBut *but, uiHandleButtonData *data,
int evtx, int evty,
bool snap, const bool shift)
{
@@ -5330,8 +5810,8 @@ static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData
cmp[a].x += fx;
cmp[a].y += fy;
if (snap) {
- cmp[a].x = 0.125f * floorf(0.5f + 8.0f * cmp[a].x);
- cmp[a].y = 0.125f * floorf(0.5f + 8.0f * cmp[a].y);
+ cmp[a].x = 0.125f * roundf(8.0f * cmp[a].x);
+ cmp[a].y = 0.125f * roundf(8.0f * cmp[a].y);
}
if (cmp[a].x != origx || cmp[a].y != origy)
moved_point = true;
@@ -5714,9 +6194,10 @@ static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, con
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const bool shift)
+static bool ui_numedit_but_TRACKPREVIEW(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const bool shift)
{
MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
bool changed = true;
@@ -5925,7 +6406,7 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
UI_popup_block_invoke(C, menu_change_shortcut, but);
}
@@ -5946,7 +6427,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;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
@@ -5995,7 +6476,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
return false;
}
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
/* highly unlikely getting the label ever fails */
UI_but_string_info_get(C, but, &label, NULL);
@@ -6064,7 +6545,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
}
- if (but->flag & UI_BUT_ANIMATED) {
+ if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) {
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1);
@@ -6211,7 +6692,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
/* Show header tools for header buttons. */
- {
+ if (ui_block_is_menu(but->block) == false) {
ARegion *ar = CTX_wm_region(C);
if (ar && (ar->regiontype == RGN_TYPE_HEADER)) {
uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
@@ -6223,14 +6704,9 @@ static bool ui_but_menu(bContext *C, uiBut *but)
char buf[512];
PointerRNA ptr_props;
- if (but->rnapoin.data && but->rnaprop) {
- BLI_snprintf(buf, sizeof(buf), "%s.%s",
- RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+ if (UI_but_online_manual_id(but, buf, sizeof(buf))) {
+ uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
+ ICON_NONE, "WM_OT_doc_view_manual_ui_context");
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
RNA_string_set(&ptr_props, "doc_id", buf);
@@ -6246,30 +6722,6 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
- else if (but->optype) {
- WM_operator_py_idname(buf, but->optype->idname);
-
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLF_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");
- RNA_string_set(&ptr_props, "doc_id", buf);
- RNA_string_set(&ptr_props, "doc_new", but->optype->description);
-
- uiItemFullO(layout, "WM_OT_doc_edit", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Submit Description"),
- ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
-#endif
- }
}
/* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
@@ -6325,7 +6777,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL);
return WM_UI_HANDLER_BREAK;
}
- else if (but->type == UI_BTYPE_SEARCH_MENU_UNLINK) {
+ else if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) {
StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
const short idcode = RNA_type_to_ID_code(type);
@@ -6482,11 +6936,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
break;
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
+ retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
+ if (retval & WM_UI_HANDLER_BREAK) {
+ break;
+ }
+ }
retval = ui_do_but_TEX(C, block, but, data, event);
break;
- case UI_BTYPE_SEARCH_MENU_UNLINK:
- retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
- break;
case UI_BTYPE_MENU:
case UI_BTYPE_BLOCK:
case UI_BTYPE_PULLDOWN:
@@ -6586,8 +7045,13 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* just to be sure, check we're dragging more hoz then virt */
abs(event->prevx - event->x) > abs(event->prevy - event->y)))
{
- ui_multibut_states_create(but, data);
- data->multi_data.init = BUTTON_MULTI_INIT_ENABLE;
+ if (data->multi_data.has_mbuts) {
+ ui_multibut_states_create(but, data);
+ data->multi_data.init = BUTTON_MULTI_INIT_ENABLE;
+ }
+ else {
+ data->multi_data.init = BUTTON_MULTI_INIT_DISABLE;
+ }
}
}
@@ -6725,7 +7189,7 @@ bool UI_but_active_drop_name(bContext *C)
uiBut *but = ui_but_find_active_in_region(ar);
if (but) {
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return 1;
}
@@ -6840,13 +7304,6 @@ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
-bool ui_but_is_search_unlink_visible(const uiBut *but)
-{
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU_UNLINK);
- return ((but->editstr == NULL) &&
- (but->drawstr[0] != '\0'));
-}
-
/* x and y are only used in case event is NULL... */
static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit)
{
@@ -6934,7 +7391,8 @@ static bool button_modal_state(uiHandleButtonState state)
BUTTON_STATE_MENU_OPEN);
}
-static void button_timers_tooltip_remove(bContext *C, uiBut *but)
+/* removes tooltip timer from active but (meaning tooltip is disabled until it's reenabled again) */
+void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data;
@@ -7018,7 +7476,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
}
else {
but->flag |= UI_SELECT;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
/* text editing */
@@ -7080,7 +7538,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (!(but->block->handle && but->block->handle->popup)) {
if (button_modal_state(state)) {
if (!button_modal_state(data->state))
- WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
+ WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, 0);
}
else {
if (button_modal_state(data->state)) {
@@ -7125,7 +7583,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU)) {
/* XXX curve is temp */
}
else {
@@ -7185,8 +7643,9 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
}
}
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree)
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree)
{
uiBlock *block = but->block;
uiBut *bt;
@@ -7258,6 +7717,10 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (data->origstr)
MEM_freeN(data->origstr);
+#ifdef USE_ALLSELECT
+ ui_selectcontext_end(but, &data->select_others);
+#endif
+
/* redraw (data is but->active!) */
ED_region_tag_redraw(data->region);
@@ -7464,7 +7927,7 @@ void UI_context_update_anim_flag(const bContext *C)
/************** handle activating a button *************/
-static uiBut *uit_but_find_open_event(ARegion *ar, const wmEvent *event)
+static uiBut *ui_but_find_open_event(ARegion *ar, const wmEvent *event)
{
uiBlock *block;
uiBut *but;
@@ -7495,7 +7958,7 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
}
}
else if (event->type == EVT_BUT_OPEN) {
- but = uit_but_find_open_event(ar, event);
+ but = ui_but_find_open_event(ar, event);
if (but) {
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
ui_do_button(C, but->block, but, event);
@@ -7599,7 +8062,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
uiBut *but_other = ui_but_find_mouse_over(ar, event);
bool exit = false;
- if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(but->block)) &&
+ /* always deactivate button for pie menus, else moving to blank space will leave activated */
+ if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(block)) &&
!ui_but_contains_point_px(ar, but, event->x, event->y))
{
exit = true;
@@ -7647,7 +8111,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case WHEELDOWNMOUSE:
case MIDDLEMOUSE:
case MOUSEPAN:
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
/* fall-through */
default:
/* handle button type specific events */
@@ -7808,7 +8272,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
if (val == KM_PRESS) {
if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
- ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+ ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl)))
{
const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop);
int value, min, max, inc;
@@ -7958,13 +8422,14 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
/* ************************* menu handling *******************************/
-/* function used to prevent loosing the open menu when using nested pulldowns,
+/**
+ * Function used to prevent loosing the open menu when using nested pulldowns,
* when moving mouse towards the pulldown menu over other buttons that could
* steal the highlight from the current button, only checks:
*
* - while mouse moves in triangular area defined old mouse position and
- * left/right side of new menu
- * - only for 1 second
+ * left/right side of new menu.
+ * - only for 1 second.
*/
static void ui_mouse_motion_towards_init_ex(uiPopupBlockHandle *menu, const int xy[2], const bool force)
@@ -7993,8 +8458,9 @@ static void ui_mouse_motion_towards_reinit(uiPopupBlockHandle *menu, const int x
ui_mouse_motion_towards_init_ex(menu, xy, true);
}
-static bool ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
- const bool use_wiggle_room)
+static bool ui_mouse_motion_towards_check(
+ uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
+ const bool use_wiggle_room)
{
float p1[2], p2[2], p3[2], p4[2];
float oldp[2] = {menu->towards_xy[0], menu->towards_xy[1]};
@@ -8182,8 +8648,9 @@ static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my, uiBut *to_bt)
*
* Without this keyboard navigation from menu's wont work.
*/
-static bool ui_menu_pass_event_to_parent_if_nonactive(uiPopupBlockHandle *menu, const uiBut *but,
- const int level, const int retval)
+static bool ui_menu_pass_event_to_parent_if_nonactive(
+ uiPopupBlockHandle *menu, const uiBut *but,
+ const int level, const int retval)
{
if ((level != 0) && (but == NULL)) {
menu->menuretval = UI_RETURN_OUT | UI_RETURN_OUT_PARENT;
@@ -8553,7 +9020,7 @@ static int ui_handle_menu_event(
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
}
else {
- printf("%s: error, but->menu_key type: %d\n", __func__, but->type);
+ printf("%s: error, but->menu_key type: %u\n", __func__, but->type);
}
break;
@@ -8622,7 +9089,7 @@ static int ui_handle_menu_event(
{
if (!but || !ui_but_contains_point_px(ar, but, event->x, event->y)) {
if (but) {
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
menu->is_grab = true;
@@ -8701,6 +9168,9 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
block = ar->uiblocks.first;
but = ui_but_find_active_in_region(ar);
+
+ BLI_assert(but);
+
data = but->active;
submenu = data->menu;
@@ -9100,7 +9570,7 @@ static int ui_handle_menus_recursive(
/* now handle events for our own menu */
if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
- const bool do_but_search = (but && ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK));
+ const bool do_but_search = (but && (but->type == UI_BTYPE_SEARCH_MENU));
if (submenu && submenu->menuretval) {
const bool do_ret_out_parent = (submenu->menuretval & UI_RETURN_OUT_PARENT) != 0;
retval = ui_handle_menu_return_submenu(C, event, menu);
@@ -9384,12 +9854,12 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
void UI_region_handlers_add(ListBase *handlers)
{
WM_event_remove_ui_handler(handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
- WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
+ WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, 0);
}
-void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
+void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const char flag)
{
- WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, accept_dbl_click);
+ WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, flag);
}
void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
@@ -9402,8 +9872,9 @@ void UI_popup_handlers_remove_all(bContext *C, ListBase *handlers)
WM_event_free_ui_handler_all(C, handlers, ui_popup_handler, ui_popup_handler_remove);
}
-bool UI_textbutton_activate_rna(const bContext *C, ARegion *ar,
- const void *rna_poin_data, const char *rna_prop_id)
+bool UI_textbutton_activate_rna(
+ const bContext *C, ARegion *ar,
+ const void *rna_poin_data, const char *rna_prop_id)
{
uiBlock *block;
uiBut *but = NULL;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 679681cb372..db1eacf57dc 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -55,6 +55,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -888,11 +889,9 @@ int UI_icon_get_height(int icon_id)
void UI_icons_init(int first_dyn_id)
{
-#ifdef WITH_HEADLESS
- (void)first_dyn_id;
-#else
- init_iconfile_list(&iconfilelist);
BKE_icons_init(first_dyn_id);
+#ifndef WITH_HEADLESS
+ init_iconfile_list(&iconfilelist);
init_internal_icons();
init_brush_icons();
init_matcap_icons();
@@ -904,10 +903,13 @@ void UI_icons_init(int first_dyn_id)
static int preview_render_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return 32;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_RENDER_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_RENDER_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
/* Create rect for the icon
@@ -923,12 +925,49 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->changed[size] = 1;
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(unsigned int), "prv_rect");
}
}
+void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
+{
+ Icon *icon = BKE_icon_get(icon_id);
+
+ if (icon) {
+ DrawInfo *di = (DrawInfo *)icon->drawinfo;
+
+ if (!di) {
+ di = icon_create_drawinfo();
+
+ icon->drawinfo = di;
+ icon->drawinfo_free = UI_icons_free_drawinfo;
+ }
+
+ if (di) {
+ if (di->type == ICON_TYPE_PREVIEW) {
+ PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
+
+ if (prv) {
+ const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
+
+ if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) {
+ return;
+ }
+
+ icon_create_rect(prv, size);
+
+ /* Always using job (background) version. */
+ ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]);
+
+ prv->flag[size] &= ~PRV_CHANGED;
+ }
+ }
+ }
+ }
+}
+
/* only called when icon has changed */
/* only call with valid pointer from UI_icon_draw */
static void icon_set_image(
@@ -940,6 +979,11 @@ static void icon_set_image(
return;
}
+ if (prv_img->flag[size] & PRV_USER_EDITED) {
+ /* user-edited preview, do not auto-update! */
+ return;
+ }
+
icon_create_rect(prv_img, size);
if (use_job) {
@@ -951,7 +995,7 @@ static void icon_set_image(
scene = CTX_data_scene(C);
}
/* Immediate version */
- ED_preview_icon_render(scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+ ED_preview_icon_render(CTX_data_main(C), scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
}
}
@@ -961,22 +1005,32 @@ PreviewImage *UI_icon_to_preview(int icon_id)
if (icon) {
DrawInfo *di = (DrawInfo *)icon->drawinfo;
- if (di && di->data.buffer.image) {
- ImBuf *bbuf;
-
- bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size, IB_rect, NULL, "<matcap buffer>");
- if (bbuf) {
- PreviewImage *prv = BKE_previewimg_create();
-
- prv->rect[0] = bbuf->rect;
+ if (di) {
+ if (di->type == ICON_TYPE_PREVIEW) {
+ PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
- prv->w[0] = bbuf->x;
- prv->h[0] = bbuf->y;
-
- bbuf->rect = NULL;
- IMB_freeImBuf(bbuf);
-
- return prv;
+ if (prv) {
+ return BKE_previewimg_copy(prv);
+ }
+ }
+ else if (di->data.buffer.image) {
+ ImBuf *bbuf;
+
+ bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size,
+ IB_rect, NULL, __func__);
+ if (bbuf) {
+ PreviewImage *prv = BKE_previewimg_create();
+
+ prv->rect[0] = bbuf->rect;
+
+ prv->w[0] = bbuf->x;
+ prv->h[0] = bbuf->y;
+
+ bbuf->rect = NULL;
+ IMB_freeImBuf(bbuf);
+
+ return prv;
+ }
}
}
}
@@ -987,6 +1041,10 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
unsigned int *rect, float alpha, const float rgb[3], const bool is_preview)
{
ImBuf *ima = NULL;
+ int draw_w = w;
+ int draw_h = h;
+ int draw_x = x;
+ int draw_y = y;
/* sanity check */
if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
@@ -1006,21 +1064,34 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
/* rect contains image in 'rendersize', we only scale if needed */
- if (rw != w && rh != h) {
+ if (rw != w || rh != h) {
+ /* preserve aspect ratio and center */
+ if (rw > rh) {
+ draw_w = w;
+ draw_h = (int)(((float)rh / (float)rw) * (float)w);
+ draw_y += (h - draw_h) / 2;
+ }
+ else if (rw < rh) {
+ draw_w = (int)(((float)rw / (float)rh) * (float)h);
+ draw_h = h;
+ draw_x += (w - draw_w) / 2;
+ }
+ /* if the image is squared, the draw_ initialization values are good */
+
/* first allocate imbuf for scaling and copy preview into it */
ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
memcpy(ima->rect, rect, rw * rh * sizeof(unsigned int));
- IMB_scaleImBuf(ima, w, h); /* scale it */
+ IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
rect = ima->rect;
}
/* draw */
if (is_preview) {
- glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
- glRasterPos2f(x, y);
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glRasterPos2f(draw_x, draw_y);
+ glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
if (ima)
@@ -1037,8 +1108,9 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
}
-static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy,
- int UNUSED(iw), int ih, float alpha, const float rgb[3])
+static void icon_draw_texture(
+ float x, float y, float w, float h, int ix, int iy,
+ int UNUSED(iw), int ih, float alpha, const float rgb[3])
{
float x1, x2, y1, y2;
@@ -1080,16 +1152,20 @@ static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy
static int get_draw_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return ICON_DEFAULT_HEIGHT;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
-static void icon_draw_size(float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
- enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
+static void icon_draw_size(
+ float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
+ enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
{
bTheme *btheme = UI_GetTheme();
Icon *icon = NULL;
@@ -1145,15 +1221,21 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else if (di->type == ICON_TYPE_PREVIEW) {
- PreviewImage *pi = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *pi = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
if (pi) {
/* no create icon on this level in code */
if (!pi->rect[size]) return; /* something has gone wrong! */
/* preview images use premul alpha ... */
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], 1.0f, NULL, is_preview);
+ if (GLEW_VERSION_1_4) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -1162,17 +1244,17 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
static void ui_id_preview_image_render_size(
const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job)
{
- if ((pi->changed[size] || !pi->rect[size])) { /* changed only ever set by dynamic icons */
+ if (((pi->flag[size] & PRV_CHANGED) || !pi->rect[size])) { /* changed only ever set by dynamic icons */
/* create the rect if necessary */
icon_set_image(C, scene, id, pi, size, use_job);
- pi->changed[size] = 0;
+ pi->flag[size] &= ~PRV_CHANGED;
}
}
void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
if (pi) {
if (big)
@@ -1184,7 +1266,7 @@ void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big,
static void ui_id_brush_render(const bContext *C, ID *id)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
enum eIconSizes i;
if (!pi)
@@ -1193,9 +1275,9 @@ static void ui_id_brush_render(const bContext *C, ID *id)
for (i = 0; i < NUM_ICON_SIZES; i++) {
/* check if rect needs to be created; changed
* only set by dynamic icons */
- if ((pi->changed[i] || !pi->rect[i])) {
+ if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) {
icon_set_image(C, NULL, id, pi, i, true);
- pi->changed[i] = 0;
+ pi->flag[i] &= ~PRV_CHANGED;
}
}
}
@@ -1206,7 +1288,7 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
Brush *br = (Brush *)id;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_icon_getid(id);
+ BKE_icon_id_ensure(id);
ui_id_brush_render(C, id);
}
else {
@@ -1268,7 +1350,7 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big)
case ID_IM: /* fall through */
case ID_WO: /* fall through */
case ID_LA: /* fall through */
- iconid = BKE_icon_getid(id);
+ iconid = BKE_icon_id_ensure(id);
/* checks if not exists, or changed */
UI_id_icon_render(C, NULL, id, big, true);
break;
@@ -1317,8 +1399,9 @@ int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big
return rnaicon;
}
-static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha,
- enum eIconSizes size, const bool nocreate)
+static void icon_draw_at_size(
+ float x, float y, int icon_id, float aspect, float alpha,
+ enum eIconSizes size, const bool nocreate)
{
int draw_size = get_draw_size(size);
icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, nocreate, false);
@@ -1356,8 +1439,8 @@ void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, 0);
}
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, ICON_SIZE_PREVIEW, size, false, true);
+ icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, true);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 03816a255ad..9461547a164 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -40,11 +40,9 @@
struct ARegion;
struct bContext;
-struct IDProperty;
struct uiHandleButtonData;
struct wmEvent;
struct wmOperatorType;
-struct wmWindow;
struct wmTimer;
struct uiStyle;
struct uiWidgetColors;
@@ -123,6 +121,14 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
+/* some buttons display icons only under special conditions
+ * (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_EYEDROPPER,
+} uiButExtraIconType;
+
/* but->pie_dir */
typedef enum RadialDirection {
UI_RADIAL_NONE = -1,
@@ -445,8 +451,9 @@ extern void ui_but_hsv_set(uiBut *but);
extern void ui_but_v3_get(uiBut *but, float vec[3]);
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
-extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
- const float mx, const float my);
+extern void ui_hsvcircle_vals_from_pos(
+ float *val_rad, float *val_dist, const rcti *rect,
+ const float mx, const float my);
extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos);
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);
@@ -459,6 +466,9 @@ extern bool ui_but_string_set_eval_num(struct bContext *C, uiBut *but, const cha
extern int ui_but_string_get_max_length(uiBut *but);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
+void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
+
extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
extern void ui_but_update(uiBut *but);
@@ -468,7 +478,6 @@ extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_but_is_search_unlink_visible(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -575,20 +584,22 @@ bool ui_searchbox_apply(uiBut *but, struct ARegion *ar);
void ui_searchbox_free(struct bContext *C, struct ARegion *ar);
void ui_but_search_refresh(uiBut *but);
-uiBlock *ui_popup_block_refresh(struct bContext *C, uiPopupBlockHandle *handle,
- ARegion *butregion, uiBut *but);
+uiBlock *ui_popup_block_refresh(
+ struct bContext *C, uiPopupBlockHandle *handle,
+ ARegion *butregion, uiBut *but);
-uiPopupBlockHandle *ui_popup_block_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg);
-uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiMenuCreateFunc create_func, void *arg);
+uiPopupBlockHandle *ui_popup_block_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg);
+uiPopupBlockHandle *ui_popup_menu_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc create_func, void *arg);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
int ui_but_menu_step(uiBut *but, int step);
-struct AutoComplete;
/* interface_panel.c */
extern int ui_handler_panel_region(struct bContext *C, const struct wmEvent *event, struct ARegion *ar);
@@ -635,7 +646,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
#ifdef WITH_INPUT_IME
void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete);
-struct wmIMEData *ui_but_get_ime_data(uiBut *but);
+struct wmIMEData *ui_but_ime_data_get(uiBut *but);
#endif
/* interface_widgets.c */
@@ -664,6 +675,7 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na
void uiStyleInit(void);
/* interface_icons.c */
+void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* resources.c */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 44c1ed474d5..a61b208278d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -356,9 +356,10 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
}
/* create buttons for an item with an RNA array */
-static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon,
- PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
- bool expand, bool slider, bool toggle, bool icon_only)
+static void ui_item_array(
+ uiLayout *layout, uiBlock *block, const char *name, int icon,
+ PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
+ bool expand, bool slider, bool toggle, bool icon_only)
{
uiStyle *style = layout->root->style;
uiBut *but;
@@ -545,8 +546,9 @@ static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
}
}
-static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
- const char *uiname, int h, bool icon_only)
+static void ui_item_enum_expand(
+ uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
+ const char *uiname, int h, bool icon_only)
{
/* XXX The way this function currently handles uiname parameter is insane and inconsistent with general UI API:
* * uiname is the *enum property* label.
@@ -681,14 +683,17 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
return but;
}
-void UI_context_active_but_prop_get_filebrowser(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
+void UI_context_active_but_prop_get_filebrowser(
+ const bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop, bool *r_is_undo)
{
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but, *prevbut;
- memset(ptr, 0, sizeof(*ptr));
- *prop = NULL;
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ *r_prop = NULL;
+ *r_is_undo = false;
if (!ar)
return;
@@ -700,8 +705,9 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C, PointerRNA *p
/* find the button before the active one */
if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
if (RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
- *ptr = prevbut->rnapoin;
- *prop = prevbut->rnaprop;
+ *r_ptr = prevbut->rnapoin;
+ *r_prop = prevbut->rnaprop;
+ *r_is_undo = (prevbut->flag & UI_BUT_UNDO) != 0;
return;
}
}
@@ -877,8 +883,9 @@ void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int ico
}
-void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
- int context, int flag)
+void uiItemsFullEnumO(
+ uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
+ int context, int flag)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
@@ -1129,8 +1136,9 @@ void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
/* RNA property items */
-static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
- int index, bool icon_only, int *r_w, int *r_h)
+static void ui_item_rna_size(
+ uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
+ int index, bool icon_only, int *r_w, int *r_h)
{
PropertyType type;
PropertySubType subtype;
@@ -1573,11 +1581,14 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
/* turn button into search button */
if (searchprop) {
- but->type = RNA_property_is_unlink(prop) ? UI_BTYPE_SEARCH_MENU_UNLINK : UI_BTYPE_SEARCH_MENU;
+ but->type = UI_BTYPE_SEARCH_MENU;
but->hardmax = MAX2(but->hardmax, 256.0f);
but->rnasearchpoin = *searchptr;
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;
+ }
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
@@ -1677,8 +1688,9 @@ static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
-static uiBut *ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
- const char *tip, bool force_menu)
+static uiBut *ui_item_menu(
+ uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
+ const char *tip, bool force_menu)
{
uiBlock *block = layout->root->block;
uiBut *but;
@@ -2139,7 +2151,11 @@ static void ui_litem_layout_column(uiLayout *litem)
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
{
RadialDirection dir;
- BLI_assert(itemnum < 8);
+
+ if (itemnum >= 8) {
+ itemnum %= 8;
+ printf("Warning: Pie menus with more than 8 items are currently unsupported\n");
+ }
dir = ui_radial_dir_order[itemnum];
ui_but_pie_dir(dir, vec);
@@ -2717,7 +2733,8 @@ uiLayout *uiLayoutBox(uiLayout *layout)
return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/* Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+/**
+ * Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
* Needed to handle correctly text colors of active (selected) list item.
*/
void ui_layout_list_set_labels_active(uiLayout *layout)
@@ -2733,8 +2750,9 @@ void ui_layout_list_set_labels_active(uiLayout *layout)
}
}
-uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
- PropertyRNA *actprop)
+uiLayout *uiLayoutListBox(
+ uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
+ PropertyRNA *actprop)
{
uiLayoutItemBx *box = ui_layout_box(layout, UI_BTYPE_LISTBOX);
uiBut *but = box->roundbox;
@@ -3333,9 +3351,10 @@ static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt,
#endif
/* this function does not initialize the layout, functions can be called on the layout before and after */
-void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
- bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
- const char label_align, const short flag)
+void uiLayoutOperatorButs(
+ const bContext *C, uiLayout *layout, wmOperator *op,
+ bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
+ const char label_align, const short flag)
{
if (!op->properties) {
IDPropertyTemplate val = {0};
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 41d2a90e548..23b20591275 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -33,6 +33,7 @@
#include "DNA_screen_types.h"
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
@@ -43,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
@@ -261,7 +263,7 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(
+bool UI_context_copy_to_selected_list(
bContext *C, PointerRNA *ptr, PropertyRNA *prop,
ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
@@ -277,6 +279,49 @@ static bool 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_Node) ||
+ RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
+ {
+ ListBase lb = {NULL, NULL};
+ char *path = NULL;
+ bNode *node = NULL;
+
+ /* Get the node we're editing */
+ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
+ bNodeTree *ntree = ptr->id.data;
+ bNodeSocket *sock = ptr->data;
+ if (nodeFindNode(ntree, sock, &node, NULL)) {
+ if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
+ /* we're good! */
+ }
+ else {
+ node = NULL;
+ }
+ }
+ }
+ else {
+ node = ptr->data;
+ }
+
+ /* Now filter by type */
+ if (node) {
+ CollectionPointerLink *link, *link_next;
+ lb = CTX_data_collection_get(C, "selected_nodes");
+
+ for (link = lb.first; link; link = link_next) {
+ bNode *node_data = link->ptr.data;
+ link_next = link->next;
+
+ if (node_data->type != node->type) {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (ptr->id.data) {
ID *id = ptr->id.data;
@@ -285,6 +330,51 @@ static bool copy_to_selected_list(
*r_use_path_from_id = true;
*r_path = RNA_path_from_ID_to_property(ptr, prop);
}
+ else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
+ /* check we're using the active object */
+ const short id_code = GS(id->name);
+ ListBase lb = CTX_data_collection_get(C, "selected_editable_objects");
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
+
+ /* de-duplicate obdata */
+ if (!BLI_listbase_is_empty(&lb)) {
+ CollectionPointerLink *link, *link_next;
+
+ for (link = lb.first; link; link = link->next) {
+ Object *ob = link->ptr.id.data;
+ if (ob->data) {
+ ID *id_data = ob->data;
+ id_data->flag |= LIB_DOIT;
+ }
+ }
+
+ for (link = lb.first; link; link = link_next) {
+ Object *ob = link->ptr.id.data;
+ ID *id_data = ob->data;
+ link_next = link->next;
+
+ if ((id_data == NULL) ||
+ (id_data->flag & LIB_DOIT) == 0 ||
+ (id_data->lib) ||
+ (GS(id_data->name) != id_code))
+ {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ else {
+ /* avoid prepending 'data' to the path */
+ RNA_id_pointer_create(id_data, &link->ptr);
+ }
+
+ if (id_data) {
+ id_data->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (GS(id->name) == ID_SCE) {
/* Sequencer's ID is scene :/ */
/* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
@@ -325,7 +415,7 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
+ if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
for (link = lb.first; link; link = link->next) {
@@ -553,8 +643,9 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-static int editsource_text_edit(bContext *C, wmOperator *op,
- char filepath[FILE_MAX], int line)
+static int editsource_text_edit(
+ bContext *C, wmOperator *op,
+ char filepath[FILE_MAX], int line)
{
struct Main *bmain = CTX_data_main(C);
Text *text;
@@ -613,6 +704,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
/* redraw and get active button python info */
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
BLI_ghashIterator_done(&ghi) == false;
@@ -667,10 +759,12 @@ static void UI_OT_editsource(wmOperatorType *ot)
}
/* ------------------------------------------------------------------------- */
-/* EditTranslation utility funcs and operator,
- * Note: this includes utility functions and button matching checks.
- * this only works in conjunction with a py operator! */
+/**
+ * EditTranslation utility funcs and operator,
+ * \note: this includes utility functions and button matching checks.
+ * this only works in conjunction with a py operator!
+ */
static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
{
char tstr[32]; /* Should be more than enough! */
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index d165e2719c5..665266edb9f 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -82,6 +82,14 @@
/* only show pin header button for pinned panels */
#define USE_PIN_HIDDEN
+/* the state of the mouse position relative to the panel */
+typedef enum uiPanelMouseState {
+ PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */
+ PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */
+ PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */
+ PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */
+} uiPanelMouseState;
+
typedef enum uiHandlePanelState {
PANEL_STATE_DRAG,
PANEL_STATE_DRAG_SCALE,
@@ -202,8 +210,9 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
}
-/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
- * See also T41704.
+/**
+ * XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
+ * See also T41704.
*/
/* #define UI_USE_PANELTAB */
@@ -560,6 +569,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
rcti headrect;
rctf itemrect;
int ofsx;
+ const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
+ const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -572,7 +583,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
{
float minx = rect->xmin;
- float maxx = rect->xmax;
+ float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
glEnable(GL_BLEND);
@@ -587,8 +598,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
else if (!(panel->runtime_flag & PNL_FIRST)) {
/* draw embossed separator */
- minx += 5.0f / block->aspect;
- maxx -= 5.0f / block->aspect;
+
+ if (is_closed_x == false) {
+ minx += 5.0f / block->aspect;
+ maxx -= 5.0f / block->aspect;
+ }
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
fdrawline(minx, y, maxx, y);
@@ -615,7 +629,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
/* horizontal title */
- if (!(panel->flag & PNL_CLOSEDX)) {
+ if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
/* itemrect smaller */
@@ -631,9 +645,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* if the panel is minimized vertically:
* (------)
*/
- if (panel->flag & PNL_CLOSEDY) {
+ if (is_closed_y) {
+ /* skip */
}
- else if (panel->flag & PNL_CLOSEDX) {
+ else if (is_closed_x) {
/* draw vertical title */
ui_draw_aligned_panel_header(style, block, &headrect, 'v');
}
@@ -680,9 +695,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
BLI_rctf_scale(&itemrect, 0.35f);
- if (panel->flag & PNL_CLOSEDY)
+ if (is_closed_y)
ui_draw_tria_rect(&itemrect, 'h');
- else if (panel->flag & PNL_CLOSEDX)
+ else if (is_closed_x)
ui_draw_tria_rect(&itemrect, 'h');
else
ui_draw_tria_rect(&itemrect, 'v');
@@ -729,11 +744,13 @@ typedef struct PanelSort {
Panel *pa, *orig;
} PanelSort;
-/* note about sorting;
+/**
+ * \note about sorting;
* the sortorder has a lower value for new panels being added.
* however, that only works to insert a single panel, when more new panels get
* added the coordinates of existing panels and the previously stored to-be-inserted
- * panels do not match for sorting */
+ * panels do not match for sorting
+ */
static int find_leftmost_panel(const void *a1, const void *a2)
{
@@ -1128,6 +1145,157 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
+static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, const Panel *pa, const int mx, const int my)
+{
+ /* open panel */
+ if (pa->flag & PNL_CLOSEDX) {
+ if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ }
+ /* outside left/right side */
+ else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) {
+ /* pass */
+ }
+ else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ /* open panel */
+ else if (!(pa->flag & PNL_CLOSEDY)) {
+ if (pa->control & UI_PNL_SCALE) {
+ if (block->rect.xmax - PNL_HEADER <= mx) {
+ if (block->rect.ymin + PNL_HEADER >= my) {
+ return PANEL_MOUSE_INSIDE_SCALE;
+ }
+ }
+ }
+ if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) {
+ if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_CONTENT;
+ }
+ }
+ }
+ return PANEL_MOUSE_OUTSIDE;
+}
+
+typedef struct uiPanelDragCollapseHandle {
+ bool was_first_open;
+ int xy_init[2];
+} uiPanelDragCollapseHandle;
+
+static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ MEM_freeN(dragcol_data);
+}
+
+static void ui_panel_drag_collapse(bContext *C, uiPanelDragCollapseHandle *dragcol_data, const int xy_dst[2])
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ uiBlock *block;
+ Panel *pa;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+ rctf rect = block->rect;
+ int oldflag;
+ const bool is_horizontal = (panel_aligned(sa, ar) == BUT_HORIZONTAL);
+
+ if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ continue;
+ }
+ oldflag = pa->flag;
+
+ /* lock one axis */
+ if (is_horizontal) {
+ xy_b_block[1] = dragcol_data->xy_init[1];
+ }
+ else {
+ xy_b_block[0] = dragcol_data->xy_init[0];
+ }
+
+ /* use cursor coords in block space */
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ /* set up rect to match header size */
+ rect.ymin = rect.ymax;
+ rect.ymax = rect.ymin + PNL_HEADER;
+ if (pa->flag & PNL_CLOSEDX) {
+ rect.xmax = rect.xmin + PNL_HEADER;
+ }
+
+ /* touch all panels between last mouse coord and the current one */
+ if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
+ /* force panel to close */
+ if (dragcol_data->was_first_open == true) {
+ pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ }
+ /* force panel to open */
+ else {
+ pa->flag &= ~PNL_CLOSED;
+ }
+
+ /* if pa->flag has changed this means a panel was opened/closed here */
+ if (pa->flag != oldflag) {
+ panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ }
+ }
+ }
+}
+
+/**
+ * Panel drag-collapse (modal handler)
+ * Clicking and dragging over panels toggles their collapse state based on the panel that was first
+ * dragged over. If it was open all affected panels incl the initial one are closed and vise versa.
+ */
+static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
+{
+ wmWindow *win = CTX_wm_window(C);
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ short retval = WM_UI_HANDLER_CONTINUE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ ui_panel_drag_collapse(C, dragcol_data, &event->x);
+
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* done! */
+ WM_event_remove_ui_handler(
+ &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, true);
+ ui_panel_drag_collapse_handler_remove(C, dragcol_data);
+ }
+ /* don't let any left-mouse event fall through! */
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ }
+
+ return retval;
+}
+
+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;
+ uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
+
+ dragcol_data->was_first_open = was_open;
+ copy_v2_v2_int(dragcol_data->xy_init, &event->x);
+
+ WM_event_add_ui_handler(
+ C, &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, 0);
+}
/* this function is supposed to call general window drawing too */
/* also it supposes a block has panel, and isn't a menu */
@@ -1187,23 +1355,39 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
ED_region_tag_redraw(ar);
}
else { /* collapse */
- if (ctrl)
+ if (ctrl) {
panels_collapse_all(sa, ar, block->panel);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&ar->v2d, 0.0f, 1.0f);
+ }
+
if (block->panel->flag & PNL_CLOSED) {
block->panel->flag &= ~PNL_CLOSED;
/* snap back up so full panel aligns with screen edge */
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = 0;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, false);
+ }
}
else if (align == BUT_HORIZONTAL) {
block->panel->flag |= PNL_CLOSEDX;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
else {
- /* snap down to bottom screen edge*/
+ /* snap down to bottom screen edge */
block->panel->flag |= PNL_CLOSEDY;
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = -block->panel->sizey;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1332,10 +1516,11 @@ void UI_panel_category_clear_all(ARegion *ar)
}
/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
-static void ui_panel_category_draw_tab(int mode, float minx, float miny, float maxx, float maxy, float rad,
- int roundboxtype,
- const bool use_highlight, const bool use_shadow,
- const unsigned char highlight_fade[3])
+static void ui_panel_category_draw_tab(
+ int mode, float minx, float miny, float maxx, float maxy, float rad,
+ int roundboxtype,
+ const bool use_highlight, const bool use_shadow,
+ const unsigned char highlight_fade[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1718,8 +1903,8 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
for (block = ar->uiblocks.last; block; block = block->prev) {
- bool inside = false, inside_header = false, inside_scale = false;
-
+ uiPanelMouseState mouse_state;
+
mx = event->x;
my = event->y;
ui_window_to_block(ar, block, &mx, &my);
@@ -1731,32 +1916,11 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
continue;
if (pa->type && pa->type->flag & PNL_NO_HEADER) /* XXX - accessed freed panels when scripts reload, need to fix. */
continue;
-
- /* clicked at panel header? */
- if (pa->flag & PNL_CLOSEDX) {
- if (block->rect.xmin <= mx && block->rect.xmin + PNL_HEADER >= mx)
- inside_header = true;
- }
- else if (block->rect.xmin > mx || block->rect.xmax < mx) {
- /* outside left/right side */
- }
- else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
- inside_header = true;
- }
- else if (!(pa->flag & PNL_CLOSEDY)) {
- /* open panel */
- if (pa->control & UI_PNL_SCALE) {
- if (block->rect.xmax - PNL_HEADER <= mx)
- if (block->rect.ymin + PNL_HEADER >= my)
- inside_scale = true;
- }
- if (block->rect.xmin <= mx && block->rect.xmax >= mx)
- if (block->rect.ymin <= my && block->rect.ymax + PNL_HEADER >= my)
- inside = true;
- }
-
+
+ mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+
/* XXX hardcoded key warning */
- if ((inside || inside_header) && event->val == KM_PRESS) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) {
if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
if (pa->flag & PNL_CLOSEDY) {
@@ -1775,13 +1939,13 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
if (ui_but_is_active(ar))
continue;
- if (inside || inside_header) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
if (event->val == KM_PRESS) {
/* open close on header */
if (ELEM(event->type, RETKEY, PADENTER)) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_handle_panel_header(C, block, mx, my, RETKEY, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1791,12 +1955,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* all inside clicks should return in break - overlapping/float panels */
retval = WM_UI_HANDLER_BREAK;
- if (inside_header) {
- ui_handle_panel_header(C, block, mx, my, 0, event->ctrl, event->shift);
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
+ ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if (inside_scale && !(pa->flag & PNL_CLOSED)) {
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1804,7 +1968,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
else if (event->type == RIGHTMOUSE) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_panel_menu(C, ar, block->panel);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1943,7 +2107,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 6e5f6af3c5f..6aabbbe76b6 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -70,8 +70,9 @@
#include "interface_intern.h"
-#define MENU_TOP 8
+#define MENU_TOP (int)(8 * UI_DPI_FAC)
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
+#define MENU_BORDER (int)(0.3f * U.widget_unit)
static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
{
@@ -179,9 +180,10 @@ typedef struct uiTooltipData {
BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max");
BLI_STATIC_ASSERT(sizeof(((uiTooltipData *)NULL)->format[0]) <= sizeof(int), "oversize");
-static void rgb_tint(float col[3],
- float h, float h_strength,
- float v, float v_strength)
+static void rgb_tint(
+ float col[3],
+ float h, float h_strength,
+ float v, float v_strength)
{
float col_hsv_from[3];
float col_hsv_to[3];
@@ -241,10 +243,10 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* tone_fg = rgb_to_grayscale(main_color); */
/* mix the colors */
- rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light grey */
+ rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light gray */
rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* light blue */
- rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* grey */
- rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark grey */
+ rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* gray */
+ rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark gray */
rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */
/* draw text */
@@ -261,7 +263,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* override text-style */
fstyle_header.shadow = 1;
- fstyle_header.shadowcolor = rgb_to_luma(tip_colors[UI_TIP_LC_MAIN]);
+ fstyle_header.shadowcolor = rgb_to_grayscale(tip_colors[UI_TIP_LC_MAIN]);
fstyle_header.shadx = fstyle_header.shady = 0;
fstyle_header.shadowalpha = 1.0f;
@@ -394,7 +396,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
}
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
@@ -815,7 +817,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->type == UI_BTYPE_SEARCH_MENU_UNLINK) ? -1 : 0;
+ data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0;
}
}
@@ -826,8 +828,8 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
{
/* thumbnail preview */
if (data->preview) {
- int butw = BLI_rcti_size_x(&data->bbox) / data->prv_cols;
- int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / data->prv_rows;
+ int butw = (BLI_rcti_size_x(&data->bbox) - 2 * MENU_BORDER) / data->prv_cols;
+ int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_BORDER) / data->prv_rows;
int row, col;
*r_rect = data->bbox;
@@ -835,10 +837,10 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
col = itemnr % data->prv_cols;
row = itemnr / data->prv_cols;
- r_rect->xmin += col * butw;
+ r_rect->xmin += MENU_BORDER + (col * butw);
r_rect->xmax = r_rect->xmin + butw;
- r_rect->ymax = data->bbox.ymax - MENU_TOP - (row * buth);
+ r_rect->ymax -= MENU_BORDER + (row * buth);
r_rect->ymin = r_rect->ymax - buth;
}
/* list view */
@@ -886,7 +888,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
- else if (but->type == UI_BTYPE_SEARCH_MENU_UNLINK) {
+ 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). */
but->editstr[0] = '\0';
@@ -1044,14 +1046,8 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
- if (data->preview) {
- ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0);
- }
- else {
- ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0, data->use_sep);
- }
+ ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
+ (a == data->active) ? UI_ACTIVE : 0);
}
/* indicate more */
@@ -1164,25 +1160,27 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
/* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
- const int margin = UI_POPUP_MARGIN;
+ const int margin_x = UI_POPUP_MARGIN;
+ const int margin_y = MENU_TOP;
+ const int search_but_h = BLI_rctf_size_y(&but->rect) + 10;
/* this case is search menu inside other menu */
/* we copy region size */
ar->winrct = butregion->winrct;
/* widget rect, in region coords */
- data->bbox.xmin = margin;
- data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin;
+ data->bbox.xmin = margin_x;
+ data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin_x;
/* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */
- data->bbox.ymin = 8 * UI_DPI_FAC;
- data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC;
+ data->bbox.ymin = margin_y;
+ data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - margin_y;
/* check if button is lower half */
if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) {
- data->bbox.ymin += BLI_rctf_size_y(&but->rect);
+ data->bbox.ymin += search_but_h;
}
else {
- data->bbox.ymax -= BLI_rctf_size_y(&but->rect);
+ data->bbox.ymax -= search_but_h;
}
}
else {
@@ -1426,7 +1424,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
if (down || top) {
if (dir1 == UI_DIR_UP && top == 0) dir1 = UI_DIR_DOWN;
if (dir1 == UI_DIR_DOWN && down == 0) dir1 = UI_DIR_UP;
- if (dir2 == UI_DIR_UP && top == 0) dir2 = UI_DIR_DOWN;
+ BLI_assert(dir2 != UI_DIR_UP);
+// if (dir2 == UI_DIR_UP && top == 0) dir2 = UI_DIR_DOWN;
if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP;
}
@@ -1638,7 +1637,7 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
}
/**
- * Called for creatign new popups and refreshing existing ones.
+ * Called for creating new popups and refreshing existing ones.
*/
uiBlock *ui_popup_block_refresh(
bContext *C, uiPopupBlockHandle *handle,
@@ -1684,13 +1683,8 @@ uiBlock *ui_popup_block_refresh(
ar->regiondata = handle;
/* set UI_BLOCK_NUMSELECT before UI_block_end() so we get alphanumeric keys assigned */
- if (but) {
- if (but->type == UI_BTYPE_PULLDOWN) {
- block->flag |= UI_BLOCK_NUMSELECT;
- }
- }
- else {
- block->flag |= UI_BLOCK_POPUP | UI_BLOCK_NUMSELECT;
+ if (but == NULL) {
+ block->flag |= UI_BLOCK_POPUP;
}
block->flag |= UI_BLOCK_LOOP;
@@ -1808,9 +1802,10 @@ uiBlock *ui_popup_block_refresh(
return block;
}
-uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg)
+uiPopupBlockHandle *ui_popup_block_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg)
{
wmWindow *window = CTX_wm_window(C);
static ARegionType type;
@@ -2571,8 +2566,9 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
return pup->block;
}
-uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but,
- uiMenuCreateFunc menu_func, void *arg)
+uiPopupBlockHandle *ui_popup_menu_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc menu_func, void *arg)
{
wmWindow *window = CTX_wm_window(C);
uiStyle *style = UI_style_get_dpi();
@@ -2619,7 +2615,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -2681,7 +2677,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
- UI_popup_handlers_add(C, &window->modalhandlers, menu, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C);
MEM_freeN(pup);
@@ -2807,7 +2803,9 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
menu->popup = true;
menu->towardstime = PIL_check_seconds_timer();
- UI_popup_handlers_add(C, &window->modalhandlers, menu, true);
+ UI_popup_handlers_add(
+ C, &window->modalhandlers,
+ menu, WM_HANDLER_ACCEPT_DBL_CLICK);
WM_event_add_mousemove(C);
MEM_freeN(pie);
@@ -2850,8 +2848,9 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
return OPERATOR_INTERFACE;
}
-int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title, const char *opname,
- const char *propname, const wmEvent *event)
+int UI_pie_menu_invoke_from_operator_enum(
+ struct bContext *C, const char *title, const char *opname,
+ const char *propname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
@@ -2867,8 +2866,9 @@ int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title,
return OPERATOR_INTERFACE;
}
-int UI_pie_menu_invoke_from_rna_enum(struct bContext *C, const char *title, const char *path,
- const wmEvent *event)
+int UI_pie_menu_invoke_from_rna_enum(
+ struct bContext *C, const char *title, const char *path,
+ const wmEvent *event)
{
PointerRNA ctx_ptr;
PointerRNA r_ptr;
@@ -2997,7 +2997,7 @@ void UI_popup_block_invoke_ex(bContext *C, uiBlockCreateFunc func, void *arg, co
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -3020,7 +3020,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -3039,17 +3039,15 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int
handle->cancel_func = confirm_cancel_operator;
handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
#endif
-void UI_popup_block_close(bContext *C, uiBlock *block)
+void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
{
+ /* if loading new .blend while popup is open, window will be NULL */
if (block->handle) {
- wmWindow *win = CTX_wm_window(C);
-
- /* if loading new .blend while popup is open, window will be NULL */
if (win) {
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 2f46c0906ae..10575fcbc54 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -64,7 +64,7 @@
/* style + theme + layout-engine = UI */
-/*
+/**
* This is a complete set of layout rules, the 'state' of the Layout
* Engine. Multiple styles are possible, defined via C or Python. Styles
* get a name, and will typically get activated per region type, like
@@ -323,10 +323,14 @@ void UI_fontstyle_draw_simple_backdrop(
/* XXX: read a style configure */
uiStyle *UI_style_get(void)
{
+#if 0
uiStyle *style = NULL;
/* offset is two struct uiStyle pointers */
- /* style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2) */;
+ style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2);
return (style != NULL) ? style : U.uistyles.first;
+#else
+ return U.uistyles.first;
+#endif
}
/* for drawing, scaled with DPI setting */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b3c31a1a644..c3b58e2d1c1 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -187,10 +187,10 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* preview thumbnails */
if (template.prv_rows > 0 && template.prv_cols > 0) {
int w = 4 * U.widget_unit * template.prv_cols;
- int h = 4 * U.widget_unit * template.prv_rows + U.widget_unit;
+ int h = 5 * U.widget_unit * template.prv_rows;
/* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
template.prv_rows, template.prv_cols, "");
@@ -273,8 +273,11 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
RNA_property_update(C, &template->ptr, template->prop);
- if (id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
+ if (id && CTX_wm_window(C)->eventstate->shift) {
+ /* only way to force-remove data (on save) */
+ id->flag &= ~LIB_FAKEUSER;
id->us = 0;
+ }
break;
case UI_ID_FAKE_USER:
@@ -359,49 +362,23 @@ static const char *template_id_browse_tip(StructRNA *type)
return N_("Browse ID data to be linked");
}
-/* Return a type-based i18n context, needed e.g. by "New" button.
+/**
+ * \return a type-based i18n context, needed e.g. by "New" button.
* In most languages, this adjective takes different form based on gender of type name...
*/
#ifdef WITH_INTERNATIONAL
static const char *template_id_context(StructRNA *type)
{
if (type) {
- switch (RNA_type_to_ID_code(type)) {
- case ID_SCE: return BLF_I18NCONTEXT_ID_SCENE;
- case ID_OB: return BLF_I18NCONTEXT_ID_OBJECT;
- case ID_ME: return BLF_I18NCONTEXT_ID_MESH;
- case ID_CU: return BLF_I18NCONTEXT_ID_CURVE;
- case ID_MB: return BLF_I18NCONTEXT_ID_METABALL;
- case ID_MA: return BLF_I18NCONTEXT_ID_MATERIAL;
- case ID_TE: return BLF_I18NCONTEXT_ID_TEXTURE;
- case ID_IM: return BLF_I18NCONTEXT_ID_IMAGE;
- case ID_LS: return BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE;
- case ID_LT: return BLF_I18NCONTEXT_ID_LATTICE;
- case ID_LA: return BLF_I18NCONTEXT_ID_LAMP;
- case ID_CA: return BLF_I18NCONTEXT_ID_CAMERA;
- case ID_WO: return BLF_I18NCONTEXT_ID_WORLD;
- case ID_SCR: return BLF_I18NCONTEXT_ID_SCREEN;
- case ID_TXT: return BLF_I18NCONTEXT_ID_TEXT;
- case ID_SPK: return BLF_I18NCONTEXT_ID_SPEAKER;
- case ID_SO: return BLF_I18NCONTEXT_ID_SOUND;
- case ID_AR: return BLF_I18NCONTEXT_ID_ARMATURE;
- case ID_AC: return BLF_I18NCONTEXT_ID_ACTION;
- case ID_NT: return BLF_I18NCONTEXT_ID_NODETREE;
- case ID_BR: return BLF_I18NCONTEXT_ID_BRUSH;
- case ID_PA: return BLF_I18NCONTEXT_ID_PARTICLESETTINGS;
- case ID_GD: return BLF_I18NCONTEXT_ID_GPENCIL;
- case ID_MC: return BLF_I18NCONTEXT_ID_MOVIECLIP;
- case ID_MSK: return BLF_I18NCONTEXT_ID_MASK;
- case ID_PAL: return BLF_I18NCONTEXT_ID_PALETTE;
- case ID_PC: return BLF_I18NCONTEXT_ID_PAINTCURVE;
- }
+ return BKE_idcode_to_translation_context(RNA_type_to_ID_code(type));
}
return BLF_I18NCONTEXT_DEFAULT;
}
#endif
-static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
- const char *newop, const char *openop, const char *unlinkop)
+static void template_ID(
+ bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
+ const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
uiBlock *block;
@@ -426,8 +403,8 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6,
TIP_(template_id_browse_tip(type)));
- but->icon = id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type);
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ ui_def_but_icon(but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type),
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if ((idfrom && idfrom->lib) || !editable)
UI_but_flag_enable(but, UI_BUT_DISABLED);
@@ -437,10 +414,9 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
else if (flag & UI_ID_BROWSE) {
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
TIP_(template_id_browse_tip(type)));
- but->icon = RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
/* default dragging of icon for id browse buttons */
UI_but_drag_set_id(but, id);
- UI_but_flag_enable(but, UI_HAS_ICON);
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
if ((idfrom && idfrom->lib) || !editable)
@@ -617,8 +593,9 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
UI_block_align_end(block);
}
-static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
+static void ui_template_id(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
{
TemplateID *template;
PropertyRNA *prop;
@@ -658,21 +635,24 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const
MEM_freeN(template);
}
-void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateID(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, 0);
}
-void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateIDBrowse(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, 0, 0);
}
-void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols)
+void uiTemplateIDPreview(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int rows, int cols)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols);
@@ -680,13 +660,15 @@ void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
/************************ ID Chooser Template ***************************/
-/* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
+/**
+ * This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
*
* - propname: property identifier for property that ID-pointer gets stored to
* - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
*/
-void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
- const char *text)
+void uiTemplateAnyID(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
+ const char *text)
{
PropertyRNA *propID, *propType;
uiLayout *split, *row, *sub;
@@ -739,7 +721,8 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co
/* ---------- */
-/* This is creating/editing RNA-Paths
+/**
+ * This is creating/editing RNA-Paths
*
* - ptr: struct which holds the path property
* - propname: property identifier for property that path gets stored to
@@ -820,10 +803,11 @@ static int modifier_is_simulation(ModifierData *md)
}
}
-static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
- ModifierData *md, int index, int cageIndex, int lastCageIndex)
+static uiLayout *draw_modifier(
+ uiLayout *layout, Scene *scene, Object *ob,
+ ModifierData *md, int index, int cageIndex, int lastCageIndex)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
PointerRNA ptr;
uiBut *but;
uiBlock *block;
@@ -1065,7 +1049,8 @@ static void do_constraint_panels(bContext *C, void *ob_pt, int event)
case B_CONSTRAINT_CHANGETARGET:
{
Main *bmain = CTX_data_main(C);
- if (ob->pose) ob->pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ if (ob->pose)
+ BKE_pose_tag_recalc(bmain, ob->pose); /* checks & sorts pose channels */
DAG_relations_tag_update(bmain);
break;
}
@@ -1095,7 +1080,7 @@ static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
{
bPoseChannel *pchan = BKE_pose_channel_active(ob);
- bConstraintTypeInfo *cti;
+ const bConstraintTypeInfo *cti;
uiBlock *block;
uiLayout *result = NULL, *col, *box, *row;
PointerRNA ptr;
@@ -1283,8 +1268,9 @@ static void do_preview_buttons(bContext *C, void *arg, int event)
}
}
-void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
- const char *preview_id)
+void uiTemplatePreview(
+ uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
+ const char *preview_id)
{
uiLayout *row, *col;
uiBlock *block;
@@ -1492,8 +1478,9 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
bt->rnapoin.data = coba->data + coba->cur;
}
-static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
- RNAUpdateCb *cb, int expand)
+static void colorband_buttons_layout(
+ uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
+ RNAUpdateCb *cb, int expand)
{
uiLayout *row, *split, *subsplit;
uiBut *bt;
@@ -1558,6 +1545,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(split, false);
uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(layout, false);
@@ -1575,6 +1563,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(subsplit, false);
uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(split, false);
@@ -1622,44 +1611,57 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
/********************* Icon viewer Template ************************/
+typedef struct IconViewMenuArgs {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int show_labels;
+} IconViewMenuArgs;
/* ID Search browse menu, open */
static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
{
- static RNAUpdateCb cb;
+ static IconViewMenuArgs args;
uiBlock *block;
uiBut *but;
- int icon;
+ int icon, value;
EnumPropertyItem *item;
int a;
bool free;
/* arg_litem is malloced, can be freed by parent button */
- cb = *((RNAUpdateCb *)arg_litem);
-
- /* unused */
- // icon = RNA_property_enum_get(&cb.ptr, cb.prop);
-
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ args = *((IconViewMenuArgs *) arg_litem);
+
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS_PULLDOWN);
UI_block_flag_enable(block, UI_BLOCK_LOOP);
-
-
- RNA_property_enum_items(C, &cb.ptr, cb.prop, &item, NULL, &free);
-
+
+ RNA_property_enum_items(C, &args.ptr, args.prop, &item, NULL, &free);
+
for (a = 0; item[a].identifier; a++) {
int x, y;
-
- /* XXX hardcoded size to 5 x unit */
- x = (a % 8) * UI_UNIT_X * 5;
- y = (a / 8) * UI_UNIT_X * 5;
-
+ /* XXX hardcoded size to 5 units */
+ const int w = UI_UNIT_X * 5;
+ const int h = args.show_labels ? 6 * UI_UNIT_Y : UI_UNIT_Y * 5;
+
+ x = (a % 8) * w;
+ y = (a / 8) * h;
+
icon = item[a].icon;
- but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, x, y, UI_UNIT_X * 5, UI_UNIT_Y * 5, &cb.ptr, cb.prop, -1, 0, icon, -1, -1, NULL);
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ value = item[a].value;
+ if (args.show_labels) {
+ but = uiDefIconTextButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, item[a].name, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ else {
+ but = uiDefIconButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
- UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_direction_set(block, UI_DIR_DOWN);
if (free) {
MEM_freeN(item);
@@ -1668,40 +1670,39 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
return block;
}
-void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname)
+void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname, int show_labels)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
- RNAUpdateCb *cb;
+ IconViewMenuArgs *cb_args;
+ EnumPropertyItem *items;
uiBlock *block;
uiBut *but;
-// rctf rect; /* UNUSED */
- int icon;
-
- if (!prop || RNA_property_type(prop) != PROP_ENUM)
+ int value, icon = ICON_NONE, tot_items;
+ bool free_items;
+
+ if (!prop || RNA_property_type(prop) != PROP_ENUM) {
+ RNA_warning("property of type Enum not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
-
- icon = RNA_property_enum_get(ptr, prop);
-
- cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
- cb->ptr = *ptr;
- cb->prop = prop;
-
-// rect.xmin = 0; rect.xmax = 10.0f * UI_UNIT_X;
-// rect.ymin = 0; rect.ymax = 10.0f * UI_UNIT_X;
-
+ }
+
block = uiLayoutAbsoluteBlock(layout);
- but = uiDefBlockButN(block, ui_icon_view_menu_cb, MEM_dupallocN(cb), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+ RNA_property_enum_items(block->evil_C, ptr, prop, &items, &tot_items, &free_items);
+ value = RNA_property_enum_get(ptr, prop);
+ RNA_enum_icon_from_value(items, value, &icon);
-
-// but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, 0, 0, BLI_rctf_size_x(&rect), BLI_rctf_size_y(&rect), ptr, prop, -1, 0, icon, -1, -1, NULL);
-
- but->icon = icon;
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
-
- UI_but_funcN_set(but, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- MEM_freeN(cb);
+ cb_args = MEM_callocN(sizeof(IconViewMenuArgs), __func__);
+ cb_args->ptr = *ptr;
+ cb_args->prop = prop;
+ cb_args->show_labels = show_labels;
+
+ but = uiDefBlockButN(block, ui_icon_view_menu_cb, cb_args, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+
+ if (free_items) {
+ MEM_freeN(items);
+ }
}
/********************* Histogram Template ************************/
@@ -2071,8 +2072,9 @@ static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
}
/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
-static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
- int brush, int neg_slope, RNAUpdateCb *cb)
+static void curvemap_buttons_layout(
+ uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
+ int brush, int neg_slope, RNAUpdateCb *cb)
{
CurveMapping *cumap = ptr->data;
CurveMap *cm = &cumap->cm[cumap->cur];
@@ -2233,8 +2235,9 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
UI_block_funcN_set(block, NULL, NULL, NULL);
}
-void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
- int levels, int brush, int neg_slope)
+void uiTemplateCurveMapping(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
+ int levels, int brush, int neg_slope)
{
RNAUpdateCb *cb;
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -2277,8 +2280,9 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
/* This template now follows User Preference for type - name is not correct anymore... */
-void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
- int lock, int lock_luminosity, int cubic)
+void uiTemplateColorPicker(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
+ int lock, int lock_luminosity, int cubic)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
uiBlock *block = uiLayoutGetBlock(layout);
@@ -2398,9 +2402,6 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
palette = cptr.data;
- /* first delete any pending colors */
- BKE_palette_cleanup(palette);
-
color = palette->colors.first;
col = uiLayoutColumn(layout, true);
@@ -2452,12 +2453,13 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/* TODO:
- * - for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags */
-
-void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_layer)
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
+void uiTemplateLayers(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_layer)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2523,8 +2525,9 @@ void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
}
}
-void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_state)
+void uiTemplateGameStates(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_state)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2594,10 +2597,11 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
/************************* List Template **************************/
-static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
- struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
- struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
- int UNUSED(index), int UNUSED(flt_flag))
+static void uilist_draw_item_default(
+ struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
+ struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
+ struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
+ int UNUSED(index), int UNUSED(flt_flag))
{
PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type);
@@ -2764,8 +2768,9 @@ typedef struct {
int end_idx; /* Index of last item to display + 1. */
} uiListLayoutdata;
-static void uilist_prepare(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
- uiListLayoutdata *layoutdata)
+static void uilist_prepare(
+ uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
+ uiListLayoutdata *layoutdata)
{
uiListDyn *dyn_data = ui_list->dyn_data;
int activei_row, max_scroll;
@@ -2851,9 +2856,10 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha
return BLI_sprintfN("%s - %s", tip, dyn_tooltip);
}
-void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
- PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
- const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
+void uiTemplateList(
+ uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+ PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
+ const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
{
uiListType *ui_list_type;
uiList *ui_list = NULL;
@@ -3199,7 +3205,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* add scrollbar */
if (len > layoutdata.visual_items) {
- col = uiLayoutColumn(row, false);
+ /* col = */ uiLayoutColumn(row, false);
uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
&ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
dyn_data->visual_height, 0, "");
@@ -3277,17 +3283,18 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0)
continue;
- if (BLI_strcasestr(ot->name, str)) {
+ if (BLI_strcasestr(ot_ui_name, str)) {
if (WM_operator_poll((bContext *)C, ot)) {
char name[256];
- int len = strlen(ot->name);
+ int len = strlen(ot_ui_name);
/* display name for menu, can hold hotkey */
- BLI_strncpy(name, ot->name, sizeof(name));
+ BLI_strncpy(name, ot_ui_name, sizeof(name));
/* check for hotkey */
if (len < sizeof(name) - 6) {
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 28bd637ae59..0823238fcb1 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -52,6 +52,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "interface_intern.h"
@@ -154,9 +157,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
* \a check_prop callback filters functions to avoid drawing certain properties,
* in cases where PROP_HIDDEN flag can't be used for a property.
*/
-int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
- bool (*check_prop)(PointerRNA *, PropertyRNA *),
- const char label_align)
+int uiDefAutoButsRNA(
+ uiLayout *layout, PointerRNA *ptr,
+ bool (*check_prop)(PointerRNA *, PropertyRNA *),
+ const char label_align)
{
uiLayout *split, *col;
int flag;
@@ -309,6 +313,34 @@ int UI_calc_float_precision(int prec, double value)
return prec;
}
+bool UI_but_online_manual_id(const uiBut *but, char *r_str, size_t maxlength)
+{
+ if (but->rnapoin.id.data && but->rnapoin.data && but->rnaprop) {
+ BLI_snprintf(r_str, maxlength, "%s.%s", RNA_struct_identifier(but->rnapoin.type),
+ RNA_property_identifier(but->rnaprop));
+ return true;
+ }
+ else if (but->optype) {
+ WM_operator_py_idname(r_str, but->optype->idname);
+ return true;
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
+bool UI_but_online_manual_id_from_active(const struct bContext *C, char *r_str, size_t maxlength)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but) {
+ return UI_but_online_manual_id(but, r_str, maxlength);
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/* Modal Button Store API */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 91186a14b49..253f4616843 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -27,7 +27,6 @@
* \ingroup edinterface
*/
-
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -56,7 +55,6 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
-
#include "interface_intern.h"
#ifdef WITH_INPUT_IME
@@ -67,12 +65,12 @@
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
/* ************** widget base functions ************** */
-/*
+/**
* - in: roundbox codes for corner types and radius
- * - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
+ * - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
*
* - draw black box with alpha 0 on exact button boundbox
- * - for ever AA step:
+ * - for every AA step:
* - draw the inner part for a round filled box, with color blend codes or texture coords
* - draw outline in outline color
* - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
@@ -102,14 +100,14 @@ typedef struct uiWidgetBase {
float inner_v[WIDGET_SIZE_MAX][2];
float inner_uv[WIDGET_SIZE_MAX][2];
- bool inner, outline, emboss, shadedir;
+ bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
uiWidgetTrias tria1;
uiWidgetTrias tria2;
} uiWidgetBase;
-/* uiWidgetType: for time being only for visual appearance,
+/** uiWidgetType: for time being only for visual appearance,
* later, a handling callback can be added too
*/
typedef struct uiWidgetType {
@@ -239,10 +237,10 @@ static void widget_init(uiWidgetBase *wtb)
wtb->tria1.tot = 0;
wtb->tria2.tot = 0;
- wtb->inner = 1;
- wtb->outline = 1;
- wtb->emboss = 1;
- wtb->shadedir = 1;
+ wtb->draw_inner = true;
+ wtb->draw_outline = true;
+ wtb->draw_emboss = true;
+ wtb->draw_shadedir = true;
}
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
@@ -549,12 +547,12 @@ static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
-
+
/* center position and size */
centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
- size = 0.4f * (float)BLI_rcti_size_y(rect);
-
+ size = 0.4f * BLI_rcti_size_y(rect);
+
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
@@ -587,7 +585,6 @@ static void widget_check_trias(uiWidgetTrias *tria, const rcti *rect)
/* prepares shade colors */
static void shadecolors4(char coltop[4], char coldown[4], const char *color, short shadetop, short shadedown)
{
-
coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
@@ -604,10 +601,10 @@ static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], c
const int faci = FTOCHAR(fac);
const int facm = 255 - faci;
- r_col[0] = (faci * col1[0] + facm * col2[0]) >> 8;
- r_col[1] = (faci * col1[1] + facm * col2[1]) >> 8;
- r_col[2] = (faci * col1[2] + facm * col2[2]) >> 8;
- r_col[3] = (faci * col1[3] + facm * col2[3]) >> 8;
+ r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
+ r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
+ r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
+ r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
}
static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
@@ -650,7 +647,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glEnable(GL_BLEND);
/* backdrop non AA */
- if (wtb->inner) {
+ if (wtb->draw_inner) {
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
@@ -716,7 +713,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glShadeModel(GL_SMOOTH);
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
- round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]);
+ round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
glEnableClientState(GL_VERTEX_ARRAY);
@@ -732,7 +729,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
/* for each AA step */
- if (wtb->outline) {
+ if (wtb->draw_outline) {
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
@@ -743,7 +740,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
- if (wtb->emboss) {
+ if (wtb->draw_emboss) {
widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
}
@@ -761,7 +758,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
/* emboss bottom shadow */
- if (wtb->emboss) {
+ if (wtb->draw_emboss) {
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
if (emboss[3]) {
@@ -783,6 +780,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
wcol->item[1],
wcol->item[2],
(unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
+
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
glTranslatef(jit[j][0], jit[j][1], 0.0f);
@@ -801,7 +799,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
glDisable(GL_BLEND);
-
}
/* *********************** text/icon ************************************** */
@@ -810,7 +807,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
#define PREVIEW_PAD 4
-static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti *rect)
+static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
{
int w, h, size;
@@ -826,7 +823,7 @@ static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti
int x = rect->xmin + w / 2 - size / 2;
int y = rect->ymin + h / 2 - size / 2;
- UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, size);
+ UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size);
}
}
@@ -838,8 +835,9 @@ static int ui_but_draw_menu_icon(const uiBut *but)
/* icons have been standardized... and this call draws in untransformed coordinates */
-static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
- const bool show_menu_icon)
+static void widget_draw_icon(
+ const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
+ const bool show_menu_icon)
{
float xs = 0.0f, ys = 0.0f;
float aspect, height;
@@ -875,7 +873,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
if (but->drawflag & UI_BUT_ICON_LEFT) {
if (but->block->flag & UI_BLOCK_LOOP) {
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
+ if (but->type == UI_BTYPE_SEARCH_MENU)
xs = rect->xmin + 4.0f * ofs;
else
xs = rect->xmin + ofs;
@@ -931,12 +929,14 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str)
but->ofs += bytes;
}
-/* Helper.
+/**
+ * Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
-static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
- const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
+static void ui_text_clip_right_ex(
+ uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
+ const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
@@ -968,11 +968,16 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m
* If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful
* for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
- const size_t max_len, const char *rpart_sep)
+float UI_text_clip_middle_ex(
+ uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep)
{
float strwidth;
+ /* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
+ * Better to have a small piece of the last char cut out, than two remaining chars replaced by an allipsis... */
+ okwidth += 1.0f + UI_DPI_FAC;
+
BLI_assert(str[0]);
/* need to set this first */
@@ -998,7 +1003,7 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
size_t final_lpart_len;
if (rpart_sep) {
- rpart = strstr(str, rpart_sep);
+ rpart = strrchr(str, rpart_sep);
if (rpart) {
rpart_len = strlen(rpart);
@@ -1069,7 +1074,7 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
}
/**
- * Wrapper around ui_text_clip_middle_ex.
+ * Wrapper around UI_text_clip_middle_ex.
*/
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
@@ -1080,14 +1085,14 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0');
}
/**
* Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep.
* Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep)
+static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
{
/* No margin for labels! */
const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
@@ -1096,7 +1101,7 @@ static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, c
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
}
/**
@@ -1217,7 +1222,6 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs, sizeof(but->drawstr) - but->ofs);
if (but->strwidth < 10) break;
}
-
}
@@ -1320,7 +1324,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
#ifdef WITH_INPUT_IME
/* FIXME, IME is modifying 'const char *drawstr! */
- ime_data = ui_but_get_ime_data(but);
+ ime_data = ui_but_ime_data_get(but);
if (ime_data && ime_data->composite_len) {
/* insert composite string into cursor pos */
@@ -1384,7 +1388,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
t = 0;
}
- glColor3f(0.20, 0.6, 0.9);
+ glColor3f(0.2, 0.6, 0.9);
tx = rect->xmin + t + 2;
ty = rect->ymin + 2;
@@ -1505,6 +1509,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
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);
@@ -1518,7 +1523,34 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
* and offset the text label to accommodate it */
- if (but->flag & UI_HAS_ICON || show_menu_icon) {
+ /* Big previews with optional text label below */
+ if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
+ const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
+ int icon_size = BLI_rcti_size_y(rect);
+ int text_size = 0;
+
+ /* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
+ if (icon_size > BLI_rcti_size_x(rect)) {
+ /* button is not square, it has extra height for label */
+ text_size = UI_UNIT_Y;
+ icon_size -= text_size;
+ }
+
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
+ glEnable(GL_BLEND);
+ widget_draw_preview(icon, alpha, rect);
+ glDisable(GL_BLEND);
+
+ /* offset rect to draw label in */
+ rect->ymin -= text_size;
+ rect->ymax -= icon_size;
+
+ /* vertically centering text */
+ rect->ymin += UI_UNIT_Y / 2;
+ }
+ /* 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);
@@ -1544,11 +1576,23 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
}
/* unlink icon for this button type */
- if ((but->type == UI_BTYPE_SEARCH_MENU_UNLINK) && ui_but_is_search_unlink_visible(but)) {
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
+ {
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+
+ if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
+ widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ }
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
+ }
+ else {
+ BLI_assert(0);
+ }
+
rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
}
@@ -1564,9 +1608,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
ui_text_clip_right_label(fstyle, but, rect);
}
- else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == UI_BTYPE_BUT)) {
+ else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
/* Clip middle, but protect in all case right part containing the shortcut, if any. */
- ui_text_clip_middle_protect_right(fstyle, but, rect, "|");
+ ui_text_clip_middle_protect_right(fstyle, but, rect, UI_SEP_CHAR);
}
else {
ui_text_clip_middle(fstyle, but, rect);
@@ -1583,17 +1627,6 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* *********************** widget types ************************************* */
-
-/* uiWidgetStateColors
- * char inner_anim[4];
- * char inner_anim_sel[4];
- * char inner_key[4];
- * char inner_key_sel[4];
- * char inner_driven[4];
- * char inner_driven_sel[4];
- * float blend;
- */
-
static struct uiWidgetStateColors wcol_state_colors = {
{115, 190, 76, 255},
{90, 166, 51, 255},
@@ -1604,18 +1637,6 @@ static struct uiWidgetStateColors wcol_state_colors = {
0.5f, 0.0f
};
-/* uiWidgetColors
- * char outline[3];
- * char inner[4];
- * char inner_sel[4];
- * char item[3];
- * char text[3];
- * char text_sel[3];
- *
- * short shaded;
- * float shadetop, shadedown;
- */
-
static struct uiWidgetColors wcol_num = {
{25, 25, 25, 255},
{180, 180, 180, 255},
@@ -1746,7 +1767,7 @@ static struct uiWidgetColors wcol_tooltip = {
{45, 45, 45, 230},
{100, 100, 100, 255},
- {160, 160, 160, 255},
+ {255, 255, 255, 255},
{255, 255, 255, 255},
0,
@@ -2181,7 +2202,7 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
glDisable(GL_BLEND);
@@ -2190,7 +2211,6 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
static void ui_hsv_cursor(float x, float y)
{
-
glPushMatrix();
glTranslatef(x, y, 0.0f);
@@ -2205,7 +2225,6 @@ static void ui_hsv_cursor(float x, float y)
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
-
}
void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
@@ -2280,12 +2299,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
* Useful for color correction tools where you're only interested in hue. */
if (but->flag & UI_BUT_COLOR_LOCK) {
if (U.color_picker_type == USER_CP_CIRCLE_HSV)
- hsv[2] = 1.f;
+ hsv[2] = 1.0f;
else
hsv[2] = 0.5f;
}
- ui_color_picker_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
+ ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
glShadeModel(GL_SMOOTH);
@@ -2331,7 +2350,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
{
/* allows for 4 steps (red->yellow) */
- const float color_step = (1.0 / 48.0);
+ const float color_step = 1.0f / 48.0f;
int a;
float h = hsv[0], s = hsv[1], v = hsv[2];
float dx, dy, sx1, sx2, sy;
@@ -2344,9 +2363,9 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
switch (type) {
case UI_GRAD_SV:
hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, 0.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, 0.0, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, 0.0, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 0.0, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(0.0, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2361,26 +2380,26 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(0.0, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
case UI_GRAD_S:
- hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
default:
assert(!"invalid 'type' argument");
- hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2401,10 +2420,10 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
/* new color */
switch (type) {
case UI_GRAD_SV:
- hsv_to_rgb(h, 0.0, dx, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, dx, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, dx, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(h, dx, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(dx_next, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2419,23 +2438,21 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(dx_next, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- {
/* annoying but without this the color shifts - could be solved some other way
* - campbell */
- hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
- }
case UI_GRAD_S:
- hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2464,9 +2481,8 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
+
glShadeModel(GL_FLAT);
-
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
@@ -2487,7 +2503,7 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
switch ((int)but->a1) {
case UI_GRAD_SV:
- x = hsv[2]; y = hsv[1]; break;
+ x = hsv[1]; y = hsv[2]; break;
case UI_GRAD_HV:
x = hsv[0]; y = hsv[2]; break;
case UI_GRAD_HS:
@@ -2509,11 +2525,10 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
y = (hsv[2] - but->softmin) / (but->softmax - but->softmin);
break;
}
-
+
/* cursor */
*xp = rect->xmin + x * BLI_rcti_size_x(rect);
*yp = rect->ymin + y * BLI_rcti_size_y(rect);
-
}
static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
@@ -2594,9 +2609,8 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
-
+
ui_hsv_cursor(x, y);
-
}
@@ -2681,7 +2695,8 @@ bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], &coord_array[0][0], resol, sizeof(float[2]));
BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], &coord_array[0][1], resol, sizeof(float[2]));
- return 1;
+ /* TODO: why return anything if always true? */
+ return true;
}
#define LINK_RESOL 24
@@ -2690,9 +2705,10 @@ void ui_draw_link_bezier(const rcti *rect)
float coord_array[LINK_RESOL + 1][2];
if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
+#if 0 /* unused */
/* we can reuse the dist variable here to increment the GL curve eval amount*/
- // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
-
+ const float dist = 1.0f / (float)LINK_RESOL;
+#endif
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -2703,7 +2719,6 @@ void ui_draw_link_bezier(const rcti *rect)
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
}
}
@@ -2725,7 +2740,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
else
rad = 0.5f * BLI_rcti_size_x(rect);
- wtb.shadedir = (horizontal) ? 1 : 0;
+ wtb.draw_shadedir = (horizontal) ? true : false;
/* draw back part, colors swapped and shading inverted */
if (horizontal)
@@ -2754,11 +2769,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
/* draw */
- wtb.emboss = 0; /* only emboss once */
+ wtb.draw_emboss = false; /* only emboss once */
/* exception for progress bar */
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
@@ -2781,7 +2796,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
widgetbase_draw(&wtb, wcol);
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
}
}
@@ -2908,7 +2923,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
toffs = offs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, offs);
- wtb.outline = 0;
+ wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
/* draw left/right parts only when not in text editing */
@@ -2933,7 +2948,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
/* left part of slider, always rounded */
rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
- wtb1.outline = 0;
+ wtb1.draw_outline = false;
widgetbase_draw(&wtb1, wcol);
/* right part of slider, interpolate roundness */
@@ -2958,8 +2973,8 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
}
/* outline */
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
/* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */
@@ -2967,7 +2982,6 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
rect->xmax -= toffs;
rect->xmin += toffs;
}
-
}
/* I think 3 is sufficient border to indicate keyed status */
@@ -3027,7 +3041,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
float width = rect->xmax - rect->xmin;
float height = rect->ymax - rect->ymin;
/* find color luminance and change it slightly */
- float bw = rgb_to_bw(col);
+ float bw = rgb_to_grayscale(col);
bw += (bw < 0.5f) ? 0.5f : -0.5f;
@@ -3052,7 +3066,7 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i
float rad;
widget_init(&wtb);
- wtb.outline = 0;
+ wtb.draw_outline = false;
/* rounded */
rad = 0.5f * BLI_rcti_size_y(rect);
@@ -3082,7 +3096,6 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
@@ -3168,7 +3181,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* not rounded, no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
round_box_edges(&wtb, 0, rect, 0.0f);
widgetbase_draw(&wtb, wcol);
@@ -3182,7 +3195,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r
widget_init(&wtb);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
rad = 0.5f * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3205,7 +3218,7 @@ static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* rounded, but no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
rad = 0.2f * U.widget_unit;
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3278,7 +3291,6 @@ static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3319,7 +3331,6 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3360,10 +3371,9 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *
/* outline */
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, &wt->wcol);
-
}
static uiWidgetType *widget_type(uiWidgetTypeEnum type)
@@ -3653,8 +3663,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_TEXT:
wt = widget_type(UI_WTYPE_NAME);
break;
-
- case UI_BTYPE_SEARCH_MENU_UNLINK:
+
case UI_BTYPE_SEARCH_MENU:
wt = widget_type(UI_WTYPE_NAME);
if (but->block->flag & UI_BLOCK_LOOP)
@@ -3931,7 +3940,6 @@ static void draw_disk_shaded(
glVertex2f(c * radius_ext, s * radius_ext);
}
glEnd();
-
}
void ui_draw_pie_center(uiBlock *block)
@@ -4020,7 +4028,6 @@ void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->draw(&wt->wcol, rect, block->flag, UI_CNR_ALL);
else
wt->draw(&wt->wcol, rect, 0, UI_CNR_ALL);
-
}
@@ -4070,7 +4077,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
UI_fontstyle_draw(fstyle, rect, drawstr);
@@ -4105,39 +4112,31 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state)
{
- rcti trect = *rect, bg_rect;
+ rcti trect = *rect;
+ const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ /* drawing button background */
wt->state(wt, state);
wt->draw(&wt->wcol, rect, 0, 0);
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
glEnable(GL_BLEND);
widget_draw_preview(iconid, 1.0f, rect);
+ glDisable(GL_BLEND);
BLF_width_and_height(fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* text rect */
trect.xmin += 0;
- trect.xmax = trect.xmin + font_dims[0] + 10;
- trect.ymin += 10;
+ trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2;
+ trect.ymin += U.widget_unit / 2;
trect.ymax = trect.ymin + font_dims[1];
if (trect.xmax > rect->xmax - PREVIEW_PAD)
trect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect = trect;
- bg_rect.xmin = rect->xmin + PREVIEW_PAD;
- bg_rect.ymin = rect->ymin + PREVIEW_PAD;
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect.ymax += PREVIEW_PAD / 2;
-
- if (bg_rect.xmax > rect->xmax - PREVIEW_PAD)
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
-
- glColor4ubv((unsigned char *)wt->wcol_theme->inner_sel);
- glRecti(bg_rect.xmin, bg_rect.ymin, bg_rect.xmax, bg_rect.ymax);
- glDisable(GL_BLEND);
-
{
char drawstr[UI_MAX_DRAW_STR];
const float okwidth = (float)BLI_rcti_size_x(&trect);
@@ -4145,7 +4144,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
UI_fontstyle_draw(fstyle, &trect, drawstr);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index a9cc53852c0..68016ae3dd8 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -569,6 +569,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->paint_curve_pivot;
break;
+ case TH_METADATA_BG:
+ cp = ts->metadatabg;
+ break;
+ case TH_METADATA_TEXT:
+ cp = ts->metadatatext;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -817,8 +824,9 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
-/* initialize default theme
- * Note: when you add new colors, created & saved themes need initialized
+/**
+ * initialize default theme
+ * \note: when you add new colors, created & saved themes need initialized
* use function below, init_userdef_do_versions()
*/
void ui_theme_init_default(void)
@@ -1098,7 +1106,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/
rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
/* space oops */
btheme->toops = btheme->tv3d;
@@ -1504,8 +1512,9 @@ void UI_GetColorPtrShade3ubv(const unsigned char cp[3], unsigned char col[3], in
}
/* get a 3 byte color, blended and shaded between two other char color pointers */
-void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
- float fac, int offset)
+void UI_GetColorPtrBlendShade3ubv(
+ const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
+ float fac, int offset)
{
int r, g, b;
@@ -1603,8 +1612,8 @@ void init_userdef_do_versions(void)
U.tw_size = 25; /* percentage of window size */
U.tw_handlesize = 16; /* percentage of widget radius */
}
- if (U.pad_rot_angle == 0)
- U.pad_rot_angle = 15;
+ if (U.pad_rot_angle == 0.0f)
+ U.pad_rot_angle = 15.0f;
/* graph editor - unselected F-Curve visibility */
if (U.fcu_inactive_alpha == 0) {
@@ -2351,7 +2360,7 @@ void init_userdef_do_versions(void)
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
}
}
@@ -2602,7 +2611,22 @@ void init_userdef_do_versions(void)
cp[3] = 255;
}
}
-
+
+ if (U.versionfile < 274 || (U.versionfile == 274 && U.subversionfile < 5)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ copy_v4_v4_char(btheme->tima.metadatatext, btheme->tima.text_hi);
+ copy_v4_v4_char(btheme->tseq.metadatatext, btheme->tseq.text_hi);
+ }
+ }
+
+ if (U.versionfile < 275 || (U.versionfile == 275 && U.subversionfile < 1)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ copy_v4_v4_char(btheme->tclip.metadatatext, btheme->tseq.text_hi);
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index b4a120b2dea..4f4b5ab07ff 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -99,11 +99,12 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src)
/* XXX still unresolved: scrolls hide/unhide vs region mask handling */
/* XXX there's V2D_SCROLL_HORIZONTAL_HIDE and V2D_SCROLL_HORIZONTAL_FULLR ... */
-/* helper to allow scrollbars to dynamically hide
- * - returns a copy of the scrollbar settings with the flags to display
- * horizontal/vertical scrollbars removed
- * - input scroll value is the v2d->scroll var
- * - hide flags are set per region at drawtime
+/**
+ * helper to allow scrollbars to dynamically hide
+ * - returns a copy of the scrollbar settings with the flags to display
+ * horizontal/vertical scrollbars removed
+ * - input scroll value is the v2d->scroll var
+ * - hide flags are set per region at drawtime
*/
static int view2d_scroll_mapped(int scroll)
{
@@ -197,11 +198,12 @@ static void view2d_masks(View2D *v2d, int check_scrollers)
/* Refresh and Validation */
-/* Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
- * - for some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - this function should only be called from region init() callbacks, where it is expected that
- * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
+/**
+ * Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
+ * - for some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - this function should only be called from region init() callbacks, where it is expected that
+ * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
*/
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
@@ -320,7 +322,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
- float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f;
+ float scrolw = (v2d->scroll & V2D_SCROLL_RIGHT) ? V2D_SCROLL_WIDTH : 0.0f;
v2d->tot.xmin = 0.0f;
v2d->tot.xmax = winx - scrolw;
@@ -361,8 +363,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
-/* Ensure View2D rects remain in a viable configuration
- * - cur is not allowed to be: larger than max, smaller than min, or outside of tot
+/**
+ * Ensure View2D rects remain in a viable configuration
+ * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers)
@@ -842,7 +845,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
-/* Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
* This does not take into account if zooming the view on an axis will improve the view (if allowed)
*/
void UI_view2d_curRect_reset(View2D *v2d)
@@ -1098,8 +1102,10 @@ void UI_view2d_view_ortho(View2D *v2d)
glLoadIdentity();
}
-/* Set view matrices to only use one axis of 'cur' only
- * - xaxis = if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
*/
void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis)
{
@@ -1192,20 +1198,23 @@ static void step_to_grid(float *step, int *power, int unit)
}
}
-/* Initialize settings necessary for drawing gridlines in a 2d-view
- * - Currently, will return pointer to View2DGrid struct that needs to
- * be freed with UI_view2d_grid_free()
- * - Is used for scrollbar drawing too (for units drawing)
- * - Units + clamping args will be checked, to make sure they are valid values that can be used
- * so it is very possible that we won't return grid at all!
- *
- * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
- * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
- * - winx = width of region we're drawing to, note: not used but keeping for completeness.
- * - winy = height of region we're drawing into
+/**
+ * Initialize settings necessary for drawing gridlines in a 2d-view
+ *
+ * - Currently, will return pointer to View2DGrid struct that needs to
+ * be freed with UI_view2d_grid_free()
+ * - Is used for scrollbar drawing too (for units drawing)
+ * - Units + clamping args will be checked, to make sure they are valid values that can be used
+ * so it is very possible that we won't return grid at all!
+ *
+ * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
+ * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
+ * - winx = width of region we're drawing to, note: not used but keeping for completeness.
+ * - winy = height of region we're drawing into
*/
-View2DGrid *UI_view2d_grid_calc(Scene *scene, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
+View2DGrid *UI_view2d_grid_calc(
+ Scene *scene, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
{
View2DGrid *grid;
@@ -1483,9 +1492,11 @@ void UI_view2d_grid_free(View2DGrid *grid)
/* *********************************************************************** */
/* Scrollers */
-/* View2DScrollers is typedef'd in UI_view2d.h
- * WARNING: the start of this struct must not change, as view2d_ops.c uses this too.
- * For now, we don't need to have a separate (internal) header for structs like this...
+/**
+ * View2DScrollers is typedef'd in UI_view2d.h
+ *
+ * \warning The start of this struct must not change, as view2d_ops.c uses this too.
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1502,8 +1513,9 @@ struct View2DScrollers {
};
/* Calculate relevant scroller properties */
-View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp)
+View2DScrollers *UI_view2d_scrollers_calc(
+ const bContext *C, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp)
{
View2DScrollers *scrollers;
rcti vert, hor;
@@ -1885,18 +1897,22 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers)
/* *********************************************************************** */
/* List View Utilities */
-/* Get the view-coordinates of the nominated cell
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - column, row = the 2d-coordinates (in 2D-view / 'tot' rect space) the cell exists at
- * - rect = coordinates of the cell (passed as single var instead of 4 separate, as it's more useful this way)
+/** Get the view-coordinates of the nominated cell
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param column, row: The 2d-coordinates
+ * (in 2D-view / 'tot' rect space) the cell exists at
+ * \param rect: coordinates of the cell
+ * (passed as single var instead of 4 separate, as it's more useful this way)
*/
-void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowheight,
- float startx, float starty,
- int column, int row, rctf *rect)
+void UI_view2d_listview_cell_to_view(
+ View2D *v2d, float columnwidth, float rowheight,
+ float startx, float starty,
+ int column, int row, rctf *rect)
{
/* sanity checks */
if (ELEM(NULL, v2d, rect)) {
@@ -1930,17 +1946,20 @@ void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowhe
}
}
-/* Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - viewx, viewy = 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * - column, row = the 'coordinates' of the relevant 'cell'
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param column, row: the 'coordinates' of the relevant 'cell'
*/
-void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- float viewx, float viewy, int *column, int *row)
+void UI_view2d_listview_view_to_cell(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ float viewx, float viewy, int *column, int *row)
{
/* adjust view coordinates to be all positive ints, corrected for the start offset */
const int x = (int)(floorf(fabsf(viewx) + 0.5f) - startx);
@@ -1967,13 +1986,16 @@ void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowhe
*row = 0;
}
-/* Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates that the list starts from, which should be (0,0) for most views
- * - column/row_min/max = the starting and ending column/row indices
+/**
+ * Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
+ *
+ * \param columnwidth, rowheight: Size of each 'cell'
+ * \param startx, starty: Coordinates that the list starts from, which should be (0,0) for most views
+ * \param column_min, column_max, row_min, row_max: The starting and ending column/row indices
*/
-void UI_view2d_listview_visible_cells(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- int *column_min, int *column_max, int *row_min, int *row_max)
+void UI_view2d_listview_visible_cells(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ int *column_min, int *column_max, int *row_min, int *row_max)
{
/* using 'cur' rect coordinates, call the cell-getting function to get the cells for this */
if (v2d) {
@@ -1999,10 +2021,11 @@ float UI_view2d_region_to_view_y(struct View2D *v2d, float y)
return (v2d->cur.ymin + (BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from screen/region space to 2d-View space
- *
- * - x,y = coordinates to convert
- * - viewx,viewy = resultant coordinates
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
*/
void UI_view2d_region_to_view(View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -2030,11 +2053,12 @@ float UI_view2d_view_to_region_y(View2D *v2d, float y)
return (v2d->mask.ymin + (((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from 2d-View space to screen/region space
- * - Coordinates are clamped to lie within bounds of region
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2057,11 +2081,13 @@ bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_
}
}
-/* Convert from 2d-view space to screen/region space
- * - Coordinates are NOT clamped to lie within bounds of region
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2175,25 +2201,30 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
}
-/* Calculate the scale per-axis of the drawing-area
- * - Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
+/**
+ * Calculate the scale per-axis of the drawing-area
*
- * - x,y = scale on each axis
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param x, y: scale on each axis
*/
void UI_view2d_scale_get(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rcti_size_x(&v2d->mask) / BLI_rctf_size_x(&v2d->cur);
if (y) *y = BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/* Same as UI_view2d_scale_get() - 1.0f / x, y */
+/**
+ * Same as ``UI_view2d_scale_get() - 1.0f / x, y``
+ */
void UI_view2d_scale_get_inverse(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
if (y) *y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
}
-/* Simple functions for consistent center offset access.
+/**
+ * Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
void UI_view2d_center_get(struct View2D *v2d, float *x, float *y)
@@ -2239,13 +2270,15 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/* Check if mouse is within scrollers
- * - Returns appropriate code for match
- * 'h' = in horizontal scroller
- * 'v' = in vertical scroller
- * 0 = not in scroller
- *
- * - x,y = mouse coordinates in screen (not region) space
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param x, y: Mouse coordinates in screen (not region) space.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
*/
short UI_view2d_mouse_in_scrollers(const bContext *C, View2D *v2d, int x, int y)
{
@@ -2288,8 +2321,9 @@ typedef struct View2DString {
static MemArena *g_v2d_strings_arena = NULL;
static View2DString *g_v2d_strings = NULL;
-void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add(
+ View2D *v2d, float x, float y,
+ const char *str, size_t str_len, const char col[4])
{
int mval[2];
@@ -2319,8 +2353,9 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
}
/* no clip (yet) */
-void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add_rectf(
+ View2D *v2d, const rctf *rect_view,
+ const char *str, size_t str_len, const char col[4])
{
rcti rect;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 88140d897ae..6fbe8509188 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -63,12 +63,13 @@ static int view2d_poll(bContext *C)
/* ********************************************************* */
/* VIEW PANNING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
- * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* ------------------ Shared 'core' stuff ---------------------- */
@@ -328,7 +329,7 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
ot->cancel = view_pan_cancel;
/* operator is modal */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
@@ -525,15 +526,18 @@ static void VIEW2D_OT_scroll_up(wmOperatorType *ot)
/* ********************************************************* */
/* SINGLE-STEP VIEW ZOOMING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount
- * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented...
- * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount.
+ * -# Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y).
+ * XXX this could be implemented...
+ * -# Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount.
*
* In order to make sure this works, each operator must define the following RNA-Operator Props:
- * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
- * It is safe to scale by 0, as these factors are used to determine
- * amount to enlarge 'cur' by
+ *
+ * - zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
+ * It is safe to scale by 0, as these factors are used to determine.
+ * amount to enlarge 'cur' by.
*/
/* ------------------ 'Shared' stuff ------------------------ */
@@ -620,8 +624,9 @@ static int view_zoom_poll(bContext *C)
}
/* apply transform to view (i.e. adjust 'cur' rect) */
-static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
- const float facx, const float facy)
+static void view_zoomstep_apply_ex(
+ bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
+ const float facx, const float facy)
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
@@ -661,7 +666,9 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
/* only move view to mouse if zoom fac is inside minzoom/maxzoom */
- if (IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom)) {
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom))
+ {
float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old);
float mval_faci = 1.0f - mval_fac;
float ofs = (mval_fac * dx) - (mval_faci * dx);
@@ -692,7 +699,9 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur);
/* only move view to mouse if zoom fac is inside minzoom/maxzoom */
- if (IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom)) {
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom))
+ {
float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old);
float mval_faci = 1.0f - mval_fac;
float ofs = (mval_fac * dy) - (mval_faci * dy);
@@ -867,10 +876,11 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
/* ********************************************************* */
/* DRAG-ZOOM OPERATOR */
-/* MMB Drag - allows non-uniform scaling by dragging mouse
+/**
+ * MMB Drag - allows non-uniform scaling by dragging mouse
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - amounts to add to each side of the 'cur' rect
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - amounts to add to each side of the 'cur' rect
*/
/* apply transform to view (i.e. adjust 'cur' rect) */
@@ -1175,7 +1185,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* operator is repeatable */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
@@ -1187,10 +1197,12 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
/* ********************************************************* */
/* BORDER-ZOOM */
-/* The user defines a rect using standard borderselect tools, and we use this rect to
+/**
+ * The user defines a rect using standard borderselect tools, and we use this rect to
* define the new zoom-level of the view in the following ways:
- * 1) LEFTMOUSE - zoom in to view
- * 2) RIGHTMOUSE - zoom out of view
+ *
+ * -# LEFTMOUSE - zoom in to view
+ * -# RIGHTMOUSE - zoom out of view
*
* Currently, these key mappings are hardcoded, but it shouldn't be too important to
* have custom keymappings for this...
@@ -1402,8 +1414,9 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
/* will start timer if appropriate */
/* the arguments are the desired situation */
-void UI_view2d_smooth_view(bContext *C, ARegion *ar,
- const rctf *cur, const int smooth_viewtx)
+void UI_view2d_smooth_view(
+ bContext *C, ARegion *ar,
+ const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -1528,13 +1541,14 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot)
/* ********************************************************* */
/* SCROLLERS */
-/* Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
- * 1) 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
- * enlarge 'cur' rect on the relevant side
- * 2) 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite)
+/**
+ * Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
+ * -# 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
+ * enlarge 'cur' rect on the relevant side.
+ * -# 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite).
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* customdata for scroller-invoke data */
@@ -1556,10 +1570,12 @@ typedef struct v2dScrollerMove {
} v2dScrollerMove;
-/* View2DScrollers is typedef'd in UI_view2d.h
+/**
+ * #View2DScrollers is typedef'd in UI_view2d.h
* This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info
- * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version
- * For now, we don't need to have a separate (internal) header for structs like this...
+ *
+ * \warning: The start of this struct must not change, so that it stays in sync with the 'real' version
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1578,10 +1594,12 @@ enum {
/* ------------------------ */
-/* check if mouse is within scroller handle
- * - mouse = relevant mouse coordinate in region space
- * - sc_min, sc_max = extents of scroller 'groove' (potential available space for scroller)
- * - sh_min, sh_max = positions of scrollbar handles
+/**
+ * Check if mouse is within scroller handle.
+ *
+ * \param mouse: relevant mouse coordinate in region space.
+ * \param sc_min, sc_max: extents of scroller 'groove' (potential available space for scroller).
+ * \param sh_min, sh_max: positions of scrollbar handles.
*/
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
{
@@ -1785,7 +1803,10 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
-/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */
+/**
+ * Handle user input for scrollers - calculations of mouse-movement need to be done here,
+ * not in the apply callback!
+ */
static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dScrollerMove *vsm = op->customdata;
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index cb47adbe73e..2dae9561d4e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -72,7 +72,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
MaskLayer *masklay, *point_masklay;
MaskSpline *point_spline;
MaskSplinePoint *point = NULL;
- float dist = FLT_MAX, co[2];
+ float dist_best_sq = FLT_MAX, co[2];
int width, height;
float u;
float scalex, scaley;
@@ -123,7 +123,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
for (j = 0; j < tot_point - 1; j++) {
- float cur_dist, a[2], b[2];
+ float dist_sq, a[2], b[2];
a[0] = points[2 * j] * scalex;
a[1] = points[2 * j + 1] * scaley;
@@ -131,16 +131,16 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
b[0] = points[2 * j + 2] * scalex;
b[1] = points[2 * j + 3] * scaley;
- cur_dist = dist_to_line_segment_v2(co, a, b);
+ dist_sq = dist_squared_to_line_segment_v2(co, a, b);
- if (cur_dist < dist) {
+ if (dist_sq < dist_best_sq) {
if (tangent)
sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
point_masklay = masklay;
point_spline = spline;
point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
- dist = cur_dist;
+ dist_best_sq = dist_sq;
u = (float)j / tot_point;
}
}
@@ -154,7 +154,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
}
- if (point && dist < threshold) {
+ if (point && dist_best_sq < threshold) {
if (masklay_r)
*masklay_r = point_masklay;
@@ -174,7 +174,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
if (score_r) {
- *score_r = dist;
+ *score_r = dist_best_sq;
}
return true;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 7e767d8f6c8..2efa9e211c9 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -253,7 +253,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
return;
if (sc)
- undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
+ undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
/* TODO, add this to sequence editor */
handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
@@ -422,7 +422,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
float (*points)[2] = orig_points;
if (sc) {
- int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
if (undistort) {
int i;
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e2eb32e86d9..e1a58d529b6 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_mask.h"
+#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "WM_api.h"
@@ -397,6 +398,58 @@ void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
}
}
+bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
+{
+ Mask *mask = CTX_data_edit_mask(C);
+ MaskLayer *mask_layer;
+ bool ok = false;
+ INIT_MINMAX2(min, max);
+ for (mask_layer = mask->masklayers.first;
+ mask_layer != NULL;
+ mask_layer = mask_layer->next)
+ {
+ MaskSpline *spline;
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ continue;
+ }
+ for (spline = mask_layer->splines.first;
+ spline != NULL;
+ spline = spline->next)
+ {
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ MaskSplinePoint *deform_point = &points_array[i];
+ BezTriple *bezt = &point->bezt;
+ float handle[2];
+ if (!MASKPOINT_ISSEL_ANY(point)) {
+ continue;
+ }
+ if (bezt->f2 & SELECT) {
+ minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]);
+ }
+ if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ else {
+ if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) {
+ BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle);
+ minmax_v2v2_v2(min, max, handle);
+ }
+ }
+ ok = true;
+ }
+ }
+ }
+ return ok;
+}
+
/********************** registration *********************/
void ED_operatortypes_mask(void)
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 5cdb224ce21..66a6c75272e 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -34,7 +34,6 @@
struct bContext;
struct Mask;
-struct wmEvent;
struct wmOperatorType;
/* internal exports only */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 113f0f71b53..35fc4483702 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -446,7 +446,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
}
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
rt = ibuf->rect;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 6ce5e8a304b..7af6c59adab 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -52,6 +52,10 @@
#include "mesh_intern.h" /* own include */
+
+#define MESH_ADD_VERTS_MAXI 10000000
+
+
/* ********* add primitive operators ************* */
static Object *make_prim_init(bContext *C, const char *idname,
@@ -62,10 +66,7 @@ static Object *make_prim_init(bContext *C, const char *idname,
*was_editmode = false;
if (obedit == NULL || obedit->type != OB_MESH) {
- obedit = ED_object_add_type(C, OB_MESH, loc, rot, false, layer);
-
- rename_id((ID *)obedit, idname);
- rename_id((ID *)obedit->data, idname);
+ obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
/* create editmode */
ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
@@ -240,7 +241,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
ED_object_add_unit_props(ot);
RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
@@ -298,9 +299,9 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
ED_object_add_unit_props(ot);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
@@ -355,12 +356,12 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500);
- prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00);
+ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
+ prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
@@ -411,8 +412,10 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "x_subdivisions", 10, 2, INT_MAX, "X Subdivisions", "", 2, 1000);
- RNA_def_int(ot->srna, "y_subdivisions", 10, 2, INT_MAX, "Y Subdivisions", "", 2, 1000);
+ /* Note that if you use MESH_ADD_VERTS_MAXI for both x and y at the same time you will still reach
+ * impossible values (10^12 vertices or so...). */
+ RNA_def_int(ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000);
+ RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
@@ -513,9 +516,9 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "segments", 32, 3, INT_MAX, "Segments", "", 3, 500);
- RNA_def_int(ot->srna, "ring_count", 16, 3, INT_MAX, "Rings", "", 3, 500);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
+ RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500);
+ RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
+ prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
ED_object_add_generic_props(ot, true);
@@ -566,8 +569,8 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "subdivisions", 2, 1, INT_MAX, "Subdivisions", "", 1, 8);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
+ RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
+ prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
ED_object_add_generic_props(ot, true);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 0e48cbcd589..cadfad34942 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -477,10 +477,10 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
- prop = RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
+ prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 6a54f1979cf..db4b0c16d9d 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -264,7 +264,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
invert_m4_m4(imat, obedit->obmat);
mul_m4_v3(imat, plane_co);
- mul_mat3_m4_v3(imat, plane_no);
+ mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
EDBM_op_init(em, &bmop, op,
"bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
@@ -335,11 +335,11 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -FLT_MAX, FLT_MAX,
- "Plane Point", "A point on the plane", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -1e12f, 1e12f,
+ "Plane Point", "A point on the plane", -1e4f, 1e4f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -FLT_MAX, FLT_MAX,
- "Plane Normal", "The direction the plane points", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -1.0f, 1.0f,
+ "Plane Normal", "The direction the plane points", -1.0f, 1.0f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut");
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 9b1b0b915c1..c4f2537eb59 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -326,8 +326,8 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, FLT_MAX, "Offset", "", 0.0f, 100.0f);
- RNA_def_int(ot->srna, "steps", 10, 0, INT_MAX, "Steps", "", 0, 180);
+ RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
+ RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
}
/* generic extern called extruder */
@@ -510,7 +510,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
float min[3], max[3];
bool done = false;
bool use_proj;
-
+
em_setup_viewcontext(C, &vc);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
@@ -574,8 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
/* correct the normal to be aligned on the view plane */
- copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(vc.obedit->imat, view_vec);
+ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
cross_v3_v3v3(cross, nor, view_vec);
cross_v3_v3v3(nor, view_vec, cross);
normalize_v3(nor);
@@ -679,7 +678,7 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
+ RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape");
}
@@ -752,13 +751,15 @@ void MESH_OT_spin(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX);
+ RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
- prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -FLT_MAX, FLT_MAX, "Angle", "Angle", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+ prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step",
+ DEG2RADF(-360.0f), DEG2RADF(360.0f));
RNA_def_property_subtype(prop, PROP_ANGLE);
- RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f);
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f,
+ "Center", "Center in global view space", -1e4f, 1e4f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
@@ -870,11 +871,11 @@ void MESH_OT_screw(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "steps", 9, 1, INT_MAX, "Steps", "Steps", 3, 256);
- RNA_def_int(ot->srna, "turns", 1, 1, INT_MAX, "Turns", "Turns", 1, 256);
+ RNA_def_int(ot->srna, "steps", 9, 1, 100000, "Steps", "Steps", 3, 256);
+ RNA_def_int(ot->srna, "turns", 1, 1, 100000, "Turns", "Turns", 1, 256);
- RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX,
- "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX,
+ RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f,
+ "Center", "Center in global view space", -1e4f, 1e4f);
+ RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
"Axis", "Axis in global view space", -1.0f, 1.0f);
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index f1c3ca30610..a5874b94edf 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -499,7 +499,7 @@ void MESH_OT_inset(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
@@ -507,10 +507,10 @@ void MESH_OT_inset(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- prop = RNA_def_float(ot->srna, "depth", 0.0f, -FLT_MAX, FLT_MAX, "Depth", "", -10.0f, 10.0f);
+ prop = RNA_def_float(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index f3745ed72fb..8775160de76 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1319,18 +1319,63 @@ static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe)
return ele_test;
}
+/* Do edges e1 and e2 go between exactly the same coordinates? */
+static bool coinciding_edges(BMEdge *e1, BMEdge *e2)
+{
+ const float *co11, *co12, *co21, *co22;
+
+ co11 = e1->v1->co;
+ co12 = e1->v2->co;
+ co21 = e2->v1->co;
+ co22 = e2->v2->co;
+ if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) ||
+ (equals_v3v3(co11, co22) && equals_v3v3(co12, co21)))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/* Callback used in point_is_visible to exclude hits on the faces that are the same
+ * as or contain the hitting element (which is in user_data).
+ * Also (see T44492) want to exclude hits on faces that butt up to the hitting element
+ * (e.g., when you double an edge by an edge split).
+ */
static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
{
+ bool ans;
+ BMEdge *e, *e2;
+ BMIter iter;
+
switch (((BMElem *)user_data)->head.htype) {
case BM_FACE:
- return (BMFace *)user_data != f;
+ ans = (BMFace *)user_data != f;
+ break;
case BM_EDGE:
- return !BM_edge_in_face((BMEdge *)user_data, f);
+ e = (BMEdge *)user_data;
+ ans = !BM_edge_in_face(e, f);
+ if (ans) {
+ /* Is it a boundary edge, coincident with a split edge? */
+ if (BM_edge_is_boundary(e)) {
+ BM_ITER_ELEM(e2, &iter, f, BM_EDGES_OF_FACE) {
+ if (coinciding_edges(e, e2)) {
+ ans = false;
+ break;
+ }
+ }
+ }
+ }
+ break;
case BM_VERT:
- return !BM_vert_in_face((BMVert *)user_data, f);
+ ans = !BM_vert_in_face((BMVert *)user_data, f);
+ break;
default:
- return true;
+ ans = true;
+ break;
}
+ return ans;
}
@@ -2783,7 +2828,7 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst;
lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e))
{
- BLI_listbase_sort_r(lst, e->v1->co, sort_verts_by_dist_cb);
+ BLI_listbase_sort_r(lst, sort_verts_by_dist_cb, e->v1->co);
for (ref = lst->first; ref; ref = ref->next) {
kfv = ref->ref;
@@ -2831,8 +2876,7 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
invert_m4_m4(kcd->projmat_inv, kcd->projmat);
- copy_v3_v3(kcd->proj_zaxis, kcd->vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(kcd->ob->imat, kcd->proj_zaxis);
+ mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]);
normalize_v3(kcd->proj_zaxis);
kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
@@ -3006,6 +3050,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_init(C, kcd, only_select, cut_through, true);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
/* add a modal handler for this operator - handles loop selection */
WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
WM_event_add_modal_handler(C, op);
@@ -3098,6 +3144,9 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
+ em_setup_viewcontext(C, &kcd->vc);
+ kcd->ar = kcd->vc.ar;
+
view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */
@@ -3257,6 +3306,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+ if (kcd->mode == MODE_DRAGGING) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_refresh) {
/* we don't really need to update mval,
* but this happens to be the best way to refresh at the moment */
@@ -3315,9 +3371,7 @@ static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3])
const float *p3 = loops[index[j][2]]->v->co;
float area;
- float cross[3];
- cross_v3_v3v3(cross, p2, p3);
- area = fabsf(dot_v3v3(p1, cross));
+ area = area_squared_tri_v3(p1, p2, p3);
if (area > area_best) {
j_best = j;
area_best = area;
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 553c1faa36a..0d3cc07589b 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -166,7 +166,7 @@ void MESH_OT_knife_project(wmOperatorType *ot)
/* callbacks */
ot->exec = knifeproject_exec;
- ot->poll = ED_operator_editmesh_view3d;
+ ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3d93210382c..74a40a23fe1 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -32,7 +32,7 @@
#include "MEM_guardedalloc.h"
-#include "BLI_array.h"
+#include "BLI_stack.h"
#include "BLI_string.h"
#include "BLI_math.h"
@@ -224,7 +224,8 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
BMEdge *eed, *eed_last;
BMVert *v[2][2] = {{NULL}}, *v_last;
float (*edges)[2][3] = NULL;
- BLI_array_declare(edges);
+ BLI_Stack *edge_stack;
+
int i, tot = 0;
BMW_init(&walker, bm, BMW_EDGERING,
@@ -232,10 +233,27 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
+
+ edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
+
+ eed_last = NULL;
+ for (eed = eed_last = BMW_begin(&walker, lcd->eed); eed; eed = BMW_step(&walker)) {
+ BLI_stack_push(edge_stack, &eed);
+ }
+ BMW_end(&walker);
+
+
+ eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
+
+ edges = MEM_mallocN(
+ (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
+
v_last = NULL;
eed_last = NULL;
- for (eed = eed_start = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
+ while (!BLI_stack_is_empty(edge_stack)) {
+ BLI_stack_pop(edge_stack, &eed);
+
if (eed_last) {
if (v_last) {
v[1][0] = v[0][0];
@@ -250,8 +268,6 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
edgering_find_order(eed_last, eed, v_last, v);
v_last = v[0][0];
- BLI_array_grow_items(edges, previewlines);
-
for (i = 1; i <= previewlines; i++) {
const float fac = (i / ((float)previewlines + 1));
float v_cos[2][2][3];
@@ -279,8 +295,6 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
edgering_find_order(eed_last, eed_start, v_last, v);
- BLI_array_grow_items(edges, previewlines);
-
for (i = 1; i <= previewlines; i++) {
const float fac = (i / ((float)previewlines + 1));
float v_cos[2][2][3];
@@ -297,7 +311,8 @@ static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, con
}
}
- BMW_end(&walker);
+ BLI_stack_free(edge_stack);
+
lcd->edges = edges;
lcd->totedge = tot;
}
@@ -553,6 +568,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
/* add a modal handler for this operator - handles loop selection */
if (is_interactive) {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
WM_event_add_modal_handler(C, op);
}
@@ -639,6 +655,9 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool show_cuts = false;
const bool has_numinput = hasNumInput(&lcd->num);
+ em_setup_viewcontext(C, &lcd->vc);
+ lcd->ar = lcd->vc.ar;
+
view3d_operator_needs_opengl(C);
/* using the keyboard to input the number of cuts */
@@ -825,21 +844,21 @@ void MESH_OT_loopcut(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 100);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000000, "Number of Cuts", "", 1, 100);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -FLT_MAX, FLT_MAX,
+ prop = RNA_def_float(ot->srna, "smoothness", 0.0f, -1e3f, 1e3f,
"Smoothness", "Smoothness factor", -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
- RNA_def_property_enum_default(prop, PROP_ROOT);
+ RNA_def_property_enum_default(prop, PROP_INVSQUARE);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
- prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Number of Cuts", "", 0, INT_MAX);
+ prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
#ifdef USE_LOOPSLIDE_HACK
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 4eaac6cc1d3..72dfb89e5f3 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -94,7 +94,7 @@ static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
float dist = ED_view3d_select_dist_px();
const bool use_length = true;
- v_dst = EDBM_vert_find_nearest(vc, &dist, false, false);
+ v_dst = EDBM_vert_find_nearest(vc, &dist);
if (v_dst) {
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
LinkNode *path = NULL;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index ead243d6de8..c7a7828f3b2 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -63,9 +63,10 @@
* point and would result in the same distance.
*/
#define INSET_DEFAULT 0.00001f
-static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2],
- const float inset)
+static float edbm_rip_edgedist_squared(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2],
+ const float inset)
{
float vec1[2], vec2[2], dist_sq;
@@ -89,8 +90,9 @@ static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
}
#if 0
-static float edbm_rip_linedist(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2])
+static float edbm_rip_linedist(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2])
{
float vec1[2], vec2[2];
@@ -114,9 +116,10 @@ static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
}
-static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l,
- ARegion *ar,
- float projectMat[4][4], const float fmval[2])
+static float edbm_rip_edge_side_measure(
+ BMEdge *e, BMLoop *e_l,
+ ARegion *ar,
+ float projectMat[4][4], const float fmval[2])
{
float cent[3] = {0, 0, 0}, mid[3];
@@ -532,14 +535,14 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, liter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totvert_orig = bm->totvert;
int i;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
float dist_sq = FLT_MAX;
float d;
- bool is_wire;
+ bool is_wire, is_manifold_region;
BMEditSelection ese;
int totboundary_edge = 0;
@@ -559,65 +562,91 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- /* this should be impossible, but sanity checks are a good thing */
- if (!v)
+ /* (v == NULL) should be impossible */
+ if ((v == NULL) || (v->e == NULL)) {
return OPERATOR_CANCELLED;
+ }
is_wire = BM_vert_is_wire(v);
+ is_manifold_region = BM_vert_is_manifold_region(v);
- e2 = NULL;
+ e_best = NULL;
- if (v->e) {
+ {
+ BMEdge *e;
/* find closest edge to mouse cursor */
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- const bool is_boundary = BM_edge_is_boundary(e);
/* consider wire as boundary for this purpose,
* otherwise we can't a face away from a wire edge */
- totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e));
+ totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if (is_boundary == false && BM_edge_is_manifold(e)) {
+ if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
+ if ((e_best == NULL) || (d < dist_sq)) {
dist_sq = d;
- e2 = e;
+ e_best = e;
}
}
}
}
+ }
- /* if we are ripping a single vertex from 3 faces,
- * then measure the distance to the face corner as well as the edge */
- if (BM_vert_face_count(v) == 3 &&
- BM_vert_edge_count(v) == 3)
- {
- BMEdge *e_all[3];
- BMLoop *l_all[3];
- int i1, i2;
-
- BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
- BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
-
- /* not do a loop similar to the one above, but test against loops */
- for (i1 = 0; i1 < 3; i1++) {
- /* consider wire as boundary for this purpose,
- * otherwise we can't a face away from a wire edge */
- float l_mid_co[3];
- l = l_all[i1];
- edbm_calc_loop_co(l, l_mid_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
- dist_sq = d;
-
- /* find the edge that is not in this loop */
- e2 = NULL;
- for (i2 = 0; i2 < 3; i2++) {
- if (!BM_edge_in_loop(e_all[i2], l)) {
- e2 = e_all[i2];
- break;
- }
+ if (e_best && (is_manifold_region == false)) {
+ /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
+ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
+ BMVert *v_new;
+
+ BLI_assert(l_sep->v == v);
+ v_new = bmesh_urmv_loop_region(bm, l_sep);
+ BLI_assert(BM_vert_find_first_loop(v));
+
+ BM_vert_select_set(bm, v, false);
+ BM_select_history_remove(bm, v);
+
+ BM_vert_select_set(bm, v_new, true);
+ if (ese.ele) {
+ BM_select_history_store(bm, v_new);
+ }
+
+ if (do_fill) {
+ BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* if we are ripping a single vertex from 3 faces,
+ * then measure the distance to the face corner as well as the edge */
+ if (BM_vert_face_count_is_equal(v, 3) &&
+ BM_vert_edge_count_is_equal(v, 3))
+ {
+ BMEdge *e_all[3];
+ BMLoop *l_all[3];
+ int i1, i2;
+
+ BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
+ BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
+
+ /* not do a loop similar to the one above, but test against loops */
+ for (i1 = 0; i1 < 3; i1++) {
+ /* consider wire as boundary for this purpose,
+ * otherwise we can't a face away from a wire edge */
+ float l_mid_co[3];
+ l = l_all[i1];
+ edbm_calc_loop_co(l, l_mid_co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
+ if ((e_best == NULL) || (d < dist_sq)) {
+ dist_sq = d;
+
+ /* find the edge that is not in this loop */
+ e_best = NULL;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!BM_edge_in_loop(e_all[i2], l)) {
+ e_best = e_all[i2];
+ break;
}
- BLI_assert(e2 != NULL);
}
+ BLI_assert(e_best != NULL);
}
}
}
@@ -677,6 +706,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
+ BMEdge *e;
/* a wire vert, find the best edge */
BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -694,6 +724,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
+ /* vout[0] == best
+ * vout[1] == glue
+ * vout[2+] == splice with glue (when vout_len > 2)
+ */
+ if (vi_best != 0) {
+ SWAP(BMVert *, vout[0], vout[vi_best]);
+ vi_best = 0;
+ }
+
/* select the vert from the best region */
v = vout[vi_best];
BM_vert_select_set(bm, v, true);
@@ -704,18 +743,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* splice all others back together */
if (vout_len > 2) {
-
- /* vout[0] == best
- * vout[1] == glue
- * vout[2+] == splice with glue
- */
- if (vi_best != 0) {
- SWAP(BMVert *, vout[0], vout[vi_best]);
- vi_best = 0;
+ for (i = 2; i < vout_len; i++) {
+ BM_vert_splice(bm, vout[1], vout[i]);
}
+ }
- for (i = 2; i < vout_len; i++) {
- BM_vert_splice(bm, vout[i], vout[1]);
+ if (do_fill) {
+ if (do_fill) {
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
}
}
@@ -725,7 +761,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- if (!e2) {
+ if (!e_best) {
BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached");
return OPERATOR_CANCELLED;
}
@@ -734,20 +770,51 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* unlike edge split, for single vertex split we only use the operator in one of the cases
* but both allocate fill */
- /* rip two adjacent edges */
- if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) {
- /* Don't run the edge split operator in this case */
+ {
BMVert *v_rip;
+ BMLoop *larr[2];
+ int larr_len = 0;
- l = BM_edge_vert_share_loop(e2->l, v);
+ /* rip two adjacent edges */
+ if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
+ /* Don't run the edge split operator in this case */
- /* only tag for face-fill (we don't call the operator) */
- if (BM_edge_is_boundary(e2)) {
- BM_elem_flag_enable(e2, BM_ELEM_TAG);
+ l = BM_edge_vert_share_loop(e_best->l, v);
+ larr[larr_len] = l;
+ larr_len++;
+
+ /* only tag for face-fill (we don't call the operator) */
+ if (BM_edge_is_boundary(e_best)) {
+ BM_elem_flag_enable(e_best, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(l->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ }
}
else {
- BM_elem_flag_enable(l->e, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ if (BM_edge_is_manifold(e_best)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_best->l;
+ do {
+ larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
+
+ if (do_fill) {
+ /* Only needed when filling...
+ * Also, we never want to tag best edge, that one won't change during split. See T44618. */
+ if (larr[larr_len]->e == e_best) {
+ BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
+ }
+ }
+ larr_len++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ else {
+ /* looks like there are no split edges, we could just return/report-error? - Campbell */
+ }
}
/* keep directly before edgesplit */
@@ -755,13 +822,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
}
-#if 0
- v_rip = BM_face_vert_separate(bm, l->f, v);
-#else
- v_rip = BM_face_loop_separate(bm, l);
-#endif
-
- BLI_assert(v_rip);
+ if (larr_len) {
+ v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
+ }
+ else {
+ v_rip = NULL;
+ }
if (v_rip) {
BM_vert_select_set(bm, v_rip, true);
@@ -771,27 +837,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
}
- else {
- if (BM_edge_is_manifold(e2)) {
- l = e2->l;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
-
- l = e2->l->radial_next;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- else {
- /* looks like there are no split edges, we could just return/report-error? - Campbell */
- }
-
- /* keep directly before edgesplit */
- if (do_fill) {
- fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
- }
-
- BM_mesh_edgesplit(em->bm, true, true, true);
- }
{
/* --- select which vert --- */
@@ -854,7 +899,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, eiter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totedge_orig = bm->totedge;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
@@ -868,11 +913,12 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* expand edge selection */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BMEdge *e;
bool all_manifold;
int totedge_manifold; /* manifold, visible edges */
int i;
- e2 = NULL;
+ e_best = NULL;
i = 0;
totedge_manifold = 0;
all_manifold = true;
@@ -884,7 +930,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* important to check selection rather then tag here
* else we get feedback loop */
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- e2 = e;
+ e_best = e;
i++;
}
totedge_manifold++;
@@ -897,18 +943,18 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
/* single edge, extend */
- if (i == 1 && e2->l) {
+ if (i == 1 && e_best->l) {
/* note: if the case of 3 edges has one change in loop stepping,
* if this becomes more involved we may be better off splitting
* the 3 edge case into its own else-if branch */
if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
- BMLoop *l_a = e2->l;
+ BMLoop *l_a = e_best->l;
BMLoop *l_b = l_a->radial_next;
/* find the best face to follow, this way the edge won't point away from
* the mouse when there are more than 4 (takes the shortest face fan around) */
- l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) <
- edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b;
+ l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
+ edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b;
l = BM_loop_other_edge_loop(l, v);
/* important edge is manifold else we can be attempting to split off a fan that don't budge,
@@ -926,7 +972,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
- e = BM_vert_other_disk_edge(v, e2);
+ e = BM_vert_other_disk_edge(v, e_best);
if (e) {
BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index d3073d519f6..27c43f9f1d3 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -36,6 +36,7 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_rand.h"
#include "BLI_array.h"
@@ -52,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -196,11 +198,11 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma
unsigned int *dr;
int a;
- if (vc->obedit == NULL || vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (buf == NULL) return false;
if (bm_vertoffs == 0) return false;
@@ -271,11 +273,11 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (buf == NULL) return false;
if (bm_vertoffs == 0) return false;
@@ -320,13 +322,13 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
xmin = xs - rads; xmax = xs + rads;
ymin = ys - rads; ymax = ys + rads;
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (bm_vertoffs == 0) return false;
if (buf == NULL) return false;
@@ -350,194 +352,369 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Find Nearest Vert/Edge/Face
+ *
+ * \note Screen-space manhatten distances are used here,
+ * since its faster and good enough for the purpose of selection.
+ *
+ * \note \a dist_bias is used so we can bias against selected items.
+ * when choosing between elements of a single type, but return the real distance
+ * to avoid the bias interfering with distance comparisons when mixing types.
+ * \{ */
+
+#define FIND_NEAR_SELECT_BIAS 5
+#define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
+
+struct NearestVertUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMVert *vert;
+};
+
+struct NearestVertUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestVertUserData_Hit hit;
+ struct NearestVertUserData_Hit hit_cycle;
+};
+
static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+ struct NearestVertUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->select) {
- if (data->strict == 1) {
- return;
- }
- else {
- dist_test += 5;
- }
- }
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.vert = eve;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = eve;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.vert == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.vert = eve;
}
}
}
-
-static bool findnearestvert__backbufIndextest(void *handle, unsigned int index)
-{
- BMEditMesh *em = (BMEditMesh *)handle;
- BMVert *eve = BM_vert_at_index_find(em->bm, index - 1);
- return !(eve && BM_elem_flag_test(eve, BM_ELEM_SELECT));
-}
/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them further than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ * Nearest vertex under the cursor.
+ *
+ * \param r_dist (in/out), minimal distance to the nearest and at the end, actual distance
+ * \param use_select_bias
+ * - When true, selected vertice are given a 5 pixel bias to make them further than unselect verts.
+ * - When false, unselected vertice are given the bias.
+ * \param use_cycle Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
*/
-BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist, const bool sel, const bool strict)
+BMVert *EDBM_vert_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle)
{
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ BMesh *bm = vc->em->bm;
+
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test;
unsigned int index;
BMVert *eve;
- if (strict) {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- strict, vc->em, findnearestvert__backbufIndextest);
- }
- else {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- 0, NULL, NULL);
- }
-
- eve = index ? BM_vert_at_index_find(vc->em->bm, index - 1) : NULL;
+ 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;
- if (eve && distance < *r_dist) {
- *r_dist = distance;
- return eve;
- }
- else {
- return NULL;
+ if (eve) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eve;
+ }
}
-
+ return NULL;
}
else {
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } data;
- static int lastSelectedIndex = 0;
- static BMVert *lastSelected = NULL;
-
- if (lastSelected && BM_vert_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ struct NearestVertUserData data = {{0}};
+ const struct NearestVertUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
+
+ static int prev_select_index = 0;
+ static const BMVert *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.select = sel ? BM_ELEM_SELECT : 0;
- data.dist = *r_dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag);
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
- if (data.dist > 3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
- }
+ prev_select_elem = hit->vert;
+ prev_select_index = hit->index;
+
+ return hit->vert;
+ }
+}
+
+BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_vert_find_nearest_ex(vc, r_dist, false, false);
+}
+
+/* find the distance to the edge we already have */
+struct NearestEdgeUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMEdge *edge_test;
+};
+
+static void find_nearest_edge_center__doZBuf(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int UNUSED(index))
+{
+ struct NearestEdgeUserData_ZBuf *data = userData;
+
+ if (eed == data->edge_test) {
+ float dist_test;
+ float screen_co_mid[2];
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
- return data.closest;
+ if (dist_test < data->dist) {
+ data->dist = dist_test;
+ }
}
}
+struct NearestEdgeUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMEdge *edge;
+
+ /* edges only, un-biased manhatten distance to which ever edge we pick
+ * (not used for choosing) */
+ float dist_center;
+};
+
+struct NearestEdgeUserData {
+ ViewContext vc;
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestEdgeUserData_Hit hit;
+ struct NearestEdgeUserData_Hit hit_cycle;
+};
+
/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
+static void find_nearest_edge__doClosest(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int index)
{
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } *data = userData;
- int distance;
+ struct NearestEdgeUserData *data = userData;
+ float dist_test, dist_test_bias;
- distance = dist_to_line_segment_v2(data->mval_fl, screen_co_a, screen_co_b);
-
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- distance += 5;
+ float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
+ float screen_co[2];
+
+ if (fac <= 0.0f) {
+ fac = 0.0f;
+ copy_v2_v2(screen_co, screen_co_a);
+ }
+ else if (fac >= 1.0f) {
+ fac = 1.0f;
+ copy_v2_v2(screen_co, screen_co_b);
+ }
+ else {
+ interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
}
- if (distance < data->dist) {
- if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
- float lambda = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
- float vec[3];
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- vec[0] = eed->v1->co[0] + lambda * (eed->v2->co[0] - eed->v1->co[0]);
- vec[1] = eed->v1->co[1] + lambda * (eed->v2->co[1] - eed->v1->co[1]);
- vec[2] = eed->v1->co[2] + lambda * (eed->v2->co[2] - eed->v1->co[2]);
+ if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ dist_test += FIND_NEAR_SELECT_BIAS;
+ }
- if (ED_view3d_clipping_test(data->vc.rv3d, vec, true) == 0) {
- data->dist = distance;
- data->closest = eed;
- }
+ if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
+ if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
+ return;
}
- else {
- data->dist = distance;
- data->closest = eed;
+ }
+
+ if (dist_test_bias < data->hit.dist_bias) {
+ float screen_co_mid[2];
+
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
+ }
+
+ if (data->use_cycle) {
+ if ((data->hit_cycle.edge == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ float screen_co_mid[2];
+
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
}
}
}
-BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist)
+
+BMEdge *EDBM_edge_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMEdge **r_eed_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test = 0.0f;
unsigned int index;
BMEdge *eed;
- view3d_validate_backbuf(vc);
-
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance, 0, NULL, NULL);
- eed = index ? BM_edge_at_index_find(vc->em->bm, index - 1) : NULL;
-
- if (eed && distance < *r_dist) {
- *r_dist = distance;
- return eed;
+ ED_view3d_backbuf_validate(vc);
+
+ index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
+ eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
+
+ if (r_eed_zbuf) {
+ *r_eed_zbuf = eed;
}
- else {
- return NULL;
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && eed) {
+ struct NearestEdgeUserData_ZBuf data;
+
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+ data.dist = FLT_MAX;
+ data.edge_test = eed;
+
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
+
+ if (eed) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eed;
+ }
}
+ return NULL;
}
else {
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } data;
+ struct NearestEdgeUserData data = {{0}};
+ const struct NearestEdgeUserData_Hit *hit;
+ /* interpolate along the edge before doing a clipping plane test */
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB;
+
+ static int prev_select_index = 0;
+ static const BMEdge *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
+ }
data.vc = *vc;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_PROJ_TEST_CLIP_WIN);
+ hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist_center;
+ }
- *r_dist = data.dist;
- return data.closest;
+ prev_select_elem = hit->edge;
+ prev_select_index = hit->index;
+
+ return hit->edge;
}
}
-static void findnearestface__getDistance(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+BMEdge *EDBM_edge_find_nearest(
+ ViewContext *vc, float *r_dist)
+{
+ return EDBM_edge_find_nearest_ex(vc, r_dist, false, false, false, NULL);
+}
+
+/* find the distance to the face we already have */
+struct NearestFaceUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMFace *face_test;
+};
+
+static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
{
- struct { float mval_fl[2]; float dist; BMFace *toFace; } *data = userData;
+ struct NearestFaceUserData_ZBuf *data = userData;
- if (efa == data->toFace) {
+ if (efa == data->face_test) {
const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if (dist_test < data->dist) {
@@ -545,96 +722,152 @@ static void findnearestface__getDistance(void *userData, BMFace *efa, const floa
}
}
}
+
+
+struct NearestFaceUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMFace *face;
+};
+
+struct NearestFaceUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestFaceUserData_Hit hit;
+ struct NearestFaceUserData_Hit hit_cycle;
+};
+
static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+ struct NearestFaceUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.face = efa;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = efa;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.face == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.face = efa;
}
}
}
-BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+
+BMFace *EDBM_face_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMFace **r_efa_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ float dist_test = 0.0f;
unsigned int index;
BMFace *efa;
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
- efa = index ? BM_face_at_index_find(vc->em->bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
+ efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
- if (efa) {
- struct { float mval_fl[2]; float dist; BMFace *toFace; } data;
+ if (r_efa_zbuf) {
+ *r_efa_zbuf = efa;
+ }
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && efa) {
+ struct NearestFaceUserData_ZBuf data;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
data.dist = FLT_MAX;
- data.toFace = efa;
+ data.face_test = efa;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
- if ((vc->em->selectmode == SCE_SELECT_FACE) || (data.dist < *r_dist)) { /* only faces, no dist check */
- *r_dist = data.dist;
+ if (efa) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
return efa;
}
}
-
return NULL;
}
else {
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } data;
- static int lastSelectedIndex = 0;
- static BMFace *lastSelected = NULL;
+ struct NearestFaceUserData data = {{0}};
+ const struct NearestFaceUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
- if (lastSelected && BM_face_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ static int prev_select_index = 0;
+ static const BMFace *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
- data.closestIndex = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
- data.pass = 0;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
- if (data.dist > 3.0f) {
- data.pass = 1;
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist;
}
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ prev_select_elem = hit->face;
+ prev_select_index = hit->index;
- return data.closest;
+ return hit->face;
}
}
+BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
+}
+
+#undef FIND_NEAR_SELECT_BIAS
+#undef FIND_NEAR_CYCLE_THRESHOLD_MIN
+
+
/* best distance based on screen coords.
* use em->selectmode to define how to use
* selected vertices and edges get disadvantage
@@ -643,35 +876,78 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
BMEditMesh *em = vc->em;
- float dist = ED_view3d_select_dist_px();
-
- *r_eve = NULL;
- *r_eed = NULL;
- *r_efa = NULL;
+ static short mval_prev[2] = {-1, -1};
+ /* only cycle while the mouse remains still */
+ const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
+ const float dist_init = ED_view3d_select_dist_px();
+ /* since edges select lines, we give dots advantage of ~20 pix */
+ const float dist_margin = (dist_init / 2);
+ float dist = dist_init;
+ BMFace *efa_zbuf = NULL;
+ BMEdge *eed_zbuf = NULL;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(vc);
-
- if (em->selectmode & SCE_SELECT_VERTEX)
- *r_eve = EDBM_vert_find_nearest(vc, &dist, BM_ELEM_SELECT, 0);
- if (em->selectmode & SCE_SELECT_FACE)
- *r_efa = EDBM_face_find_nearest(vc, &dist);
+ ED_view3d_backbuf_validate(vc);
- dist -= 20; /* since edges select lines, we give dots advantage of 20 pix */
- if (em->selectmode & SCE_SELECT_EDGE)
- *r_eed = EDBM_edge_find_nearest(vc, &dist);
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
+ efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
+ if (efa && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
+
+ if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
+ eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
+ if (eed && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
+
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
+ eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
+ }
/* return only one of 3 pointers, for frontbuffer redraws */
- if (*r_eed) {
- *r_efa = NULL; *r_eve = NULL;
+ if (eve) {
+ efa = NULL; eed = NULL;
}
- else if (*r_efa) {
- *r_eve = NULL;
+ else if (eed) {
+ efa = NULL;
}
-
- return (*r_eve || *r_eed || *r_efa);
+
+ /* there may be a face under the cursor, who's center if too far away
+ * use this if all else fails, it makes sense to select this */
+ if ((eve || eed || efa) == 0) {
+ if (eed_zbuf) {
+ eed = eed_zbuf;
+ }
+ else if (efa_zbuf) {
+ efa = efa_zbuf;
+ }
+ }
+
+ mval_prev[0] = vc->mval[0];
+ mval_prev[1] = vc->mval[1];
+
+ *r_eve = eve;
+ *r_eed = eed;
+ *r_efa = efa;
+
+ return (eve || eed || efa);
}
+/** \} */
+
+
/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
static EnumPropertyItem prop_similar_compare_types[] = {
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
@@ -923,7 +1199,7 @@ void MESH_OT_select_similar(wmOperatorType *ot)
RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
- RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.0, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
@@ -1179,7 +1455,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
else {
for (edindex = 0; edindex < totedgesel; edindex += 1) {
eed = edarray[edindex];
- walker_select(em, BMW_LOOP, eed, true);
+ walker_select(em, BMW_EDGELOOP, eed, true);
}
EDBM_selectmode_flush(em);
}
@@ -1237,12 +1513,12 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
{
bool edge_boundary = false;
- /* cycle between BMW_LOOP / BMW_EDGEBOUNDARY */
+ /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */
if (select_cycle && BM_edge_is_boundary(eed)) {
int tot[2];
/* if the loops selected toggle the boundaries */
- walker_select_count(em, BMW_LOOP, eed, select, false,
+ walker_select_count(em, BMW_EDGELOOP, eed, select, false,
&tot[0], &tot[1]);
if (tot[select] == 0) {
edge_boundary = true;
@@ -1264,7 +1540,7 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
walker_select(em, BMW_EDGEBOUNDARY, eed, select);
}
else {
- walker_select(em, BMW_LOOP, eed, select);
+ walker_select(em, BMW_EDGELOOP, eed, select);
}
}
@@ -1286,7 +1562,7 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
em = vc.em;
/* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
+ ED_view3d_backbuf_validate(&vc);
eed = EDBM_edge_find_nearest(&vc, &dist);
if (eed == NULL) {
@@ -2042,7 +2318,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
ok = true;
BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
- if (BM_edge_face_count(eed) < 3) {
+ if (!BM_edge_face_count_is_over(eed, 2)) {
ok = false;
break;
}
@@ -2060,16 +2336,98 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
/************************ Select Linked Operator *************************/
-static void linked_limit_default(bContext *C, wmOperator *op)
+struct DelimitData {
+ int cd_loop_type;
+ int cd_loop_offset;
+};
+
+static bool select_linked_delimit_test(
+ BMEdge *e, int delimit,
+ const struct DelimitData *delimit_data)
{
- if (!RNA_struct_property_is_set(op->ptr, "limit")) {
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->selectmode == SCE_SELECT_FACE)
- RNA_boolean_set(op->ptr, "limit", true);
- else
- RNA_boolean_set(op->ptr, "limit", false);
+ BLI_assert(delimit);
+
+ if (delimit & BMO_DELIM_SEAM) {
+ if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_SHARP) {
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_NORMAL) {
+ if (!BM_edge_is_contiguous(e)) {
+ return true;
+ }
}
+
+ if (delimit & BMO_DELIM_MATERIAL) {
+ if (e->l && e->l->radial_next != e->l) {
+ const short mat_nr = e->l->f->mat_nr;
+ BMLoop *l_iter = e->l->radial_next;
+ do {
+ if (l_iter->f->mat_nr != mat_nr) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+
+ if (delimit & BMO_DELIM_UV) {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit)
+{
+ struct DelimitData delimit_data = {0};
+
+ BMIter iter;
+ BMEdge *e;
+
+ if (delimit & BMO_DELIM_UV) {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
+ if (delimit_data.cd_loop_offset == -1) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ }
+
+ /* grr, shouldn't need to alloc BMO flags here */
+ BM_mesh_elem_toolflags_ensure(bm);
+ if (selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+ else {
+ /* don't delimit selected edges in vert/edge mode */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ BM_elem_flag_test(e, BM_ELEM_SELECT) ||
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+}
+
+static void select_linked_delimit_end(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ BM_mesh_elem_toolflags_clear(bm);
}
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
@@ -2078,72 +2436,139 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMIter iter;
- BMEdge *e;
BMWalker walker;
- int limit;
-
- linked_limit_default(C, op);
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (delimit) {
+ select_linked_delimit_begin(em->bm, em->selectmode, delimit);
+ }
- if (em->selectmode == SCE_SELECT_FACE) {
- BMFace *efa;
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(efa, BM_ELEM_TAG, BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
}
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, v) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(em->bm, v_step, true);
+ BM_elem_flag_disable(v_step, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, v) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
+ }
}
}
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
+
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, true);
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, e) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMLoop *l_step = (BMLoop *)ele_walk;
+ BM_edge_select_set(em->bm, l_step->e, true);
+ BM_edge_select_set(em->bm, l_step->prev->e, true);
+ BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step, BM_ELEM_TAG);
+ }
+ }
}
}
}
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, e) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
BMW_end(&walker);
- if (limit) {
- BM_mesh_elem_toolflags_clear(bm);
- }
+ EDBM_selectmode_flush(em);
}
else {
- BMVert *v;
+ BMFace *f;
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
}
- BMW_init(&walker, em->bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- for (e = BMW_begin(&walker, v); e; e = BMW_step(&walker)) {
- BM_edge_select_set(em->bm, e, true);
- BM_elem_flag_disable(e, BM_ELEM_TAG);
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, f) {
+ BM_face_select_set(bm, f_walk, true);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
}
}
}
+
BMW_end(&walker);
+ }
- EDBM_selectmode_flush(em);
+ if (delimit) {
+ select_linked_delimit_end(em);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2165,99 +2590,209 @@ void MESH_OT_select_linked(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+}
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
+
+static void edbm_select_linked_pick_ex(
+ BMEditMesh *em,
+ BMVert *eve, BMEdge *eed, BMFace *efa,
+ bool sel, int delimit)
+{
+ BMesh *bm = em->bm;
+ BMWalker walker;
+
+ if (delimit) {
+ select_linked_delimit_begin(bm, em->selectmode, delimit);
+ }
+
+ /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
+
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eve) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(bm, v_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eve) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eed) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMEdge *e_step = ((BMLoop *)ele_walk)->e;
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eed) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, efa) {
+ BM_face_select_set(bm, f_walk, sel);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
+ }
+ }
+
+ BMW_end(&walker);
+ }
+
+ if (delimit) {
+ select_linked_delimit_end(em);
+ }
}
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
- BMesh *bm;
- BMWalker walker;
BMEditMesh *em;
+ BMesh *bm;
BMVert *eve;
- BMEdge *e, *eed;
+ BMEdge *eed;
BMFace *efa;
const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+ int index;
- int limit;
-
- linked_limit_default(C, op);
-
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (RNA_struct_property_is_set(op->ptr, "index")) {
+ return edbm_select_linked_pick_exec(C, op);
+ }
/* unified_finednearest needs ogl */
view3d_operator_needs_opengl(C);
-
+
/* setup view context for argument to callbacks */
em_setup_viewcontext(C, &vc);
em = vc.em;
+ bm = em->bm;
- if (em->bm->totedge == 0)
+ if (bm->totedge == 0) {
return OPERATOR_CANCELLED;
-
- bm = em->bm;
+ }
vc.mval[0] = event->mval[0];
vc.mval[1] = event->mval[1];
-
+
/* return warning! */
-
if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
-
+
return OPERATOR_CANCELLED;
}
-
- if (em->selectmode == SCE_SELECT_FACE) {
- BMIter iter;
-
- if (efa == NULL)
- return OPERATOR_CANCELLED;
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- /* hflag no-seam --> bmo-tag */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
- }
- }
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
- /* walk */
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
-
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, sel);
- }
- BMW_end(&walker);
+ /* to support redo */
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ index = BM_elem_index_get(eve);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+ index = BM_elem_index_get(eed) + bm->totvert;
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ index = BM_elem_index_get(efa) + bm->totvert + bm->totedge;
}
else {
- if (efa) {
- eed = BM_FACE_FIRST_LOOP(efa)->e;
- }
- else if (!eed) {
- if (!eve || !eve->e)
- return OPERATOR_CANCELLED;
+ index = -1;
+ }
- eed = eve->e;
- }
+ RNA_int_set(op->ptr, "index", index);
- BMW_init(&walker, bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
- for (e = BMW_begin(&walker, eed->v1); e; e = BMW_step(&walker)) {
- BM_edge_select_set(bm, e, sel);
- }
- BMW_end(&walker);
+ return OPERATOR_FINISHED;
+}
- EDBM_selectmode_flush(em);
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int index;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+ const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+
+ index = RNA_int_get(op->ptr, "index");
+ if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (index < bm->totvert) {
+ eve = BM_vert_at_index_find_or_table(bm, index);
}
+ else if (index < (bm->totvert + bm->totedge)) {
+ index -= bm->totvert;
+ eed = BM_edge_at_index_find_or_table(bm, index);
+ }
+ else if (index < (bm->totvert + bm->totedge + bm->totface)) {
+ index -= (bm->totvert + bm->totedge);
+ efa = BM_face_at_index_find_or_table(bm, index);
+ }
+
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2266,6 +2801,8 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
void MESH_OT_select_linked_pick(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select Linked";
ot->idname = "MESH_OT_select_linked_pick";
@@ -2273,13 +2810,19 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_select_linked_pick_invoke;
+ ot->exec = edbm_select_linked_pick_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+
+ /* use for redo */
+ prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -2552,7 +3095,7 @@ static bool bm_edge_is_select_isolated(BMEdge *e)
/* Walk all reachable elements of the same type as h_act in breadth-first
* order, starting from h_act. Deselects elements if the depth when they
* are reached is not a multiple of "nth". */
-static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
+static void walker_deselect_nth(BMEditMesh *em, int nth, int skip, int offset, BMHeader *h_act)
{
BMElem *ele;
BMesh *bm = em->bm;
@@ -2618,7 +3161,8 @@ static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h
for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
- if ((offset + BMW_current_depth(&walker)) % nth) {
+ const int depth = BMW_current_depth(&walker) - 1;
+ if ((offset + depth) % (skip + nth) >= skip) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -2685,7 +3229,7 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed,
}
}
-static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
+static bool edbm_deselect_nth(BMEditMesh *em, int nth, int skip, int offset)
{
BMVert *v;
BMEdge *e;
@@ -2694,15 +3238,15 @@ static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
deselect_nth_active(em, &v, &e, &f);
if (v) {
- walker_deselect_nth(em, nth, offset, &v->head);
+ walker_deselect_nth(em, nth, skip, offset, &v->head);
return true;
}
else if (e) {
- walker_deselect_nth(em, nth, offset, &e->head);
+ walker_deselect_nth(em, nth, skip, offset, &e->head);
return true;
}
else if (f) {
- walker_deselect_nth(em, nth, offset, &f->head);
+ walker_deselect_nth(em, nth, skip, offset, &f->head);
return true;
}
@@ -2713,15 +3257,14 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int nth = RNA_int_get(op->ptr, "nth");
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
int offset = RNA_int_get(op->ptr, "offset");
/* so input of offset zero ends up being (nth - 1) */
- offset = mod_i(offset, nth);
- /* depth starts at 1, this keeps active item selected */
- offset -= 1;
+ offset = mod_i(offset, nth + skip);
- if (edbm_deselect_nth(em, nth, offset) == false) {
+ if (edbm_deselect_nth(em, nth, skip, offset) == false) {
BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
return OPERATOR_CANCELLED;
}
@@ -2747,6 +3290,7 @@ void MESH_OT_select_nth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
}
@@ -2937,7 +3481,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
if ((use_wire && BM_edge_is_wire(e)) ||
(use_boundary && BM_edge_is_boundary(e)) ||
(use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
- (use_multi_face && (BM_edge_face_count(e) > 2)))
+ (use_multi_face && (BM_edge_face_count_is_over(e, 2))))
{
/* check we never select perfect edge (in test above) */
BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
@@ -3047,8 +3591,8 @@ void MESH_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
+ RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
WM_operator_properties_select_action_simple(ot, SEL_SELECT);
}
@@ -3136,7 +3680,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op)
else {
BMVert *v;
BMIter iter;
- const float limit = CTX_data_tool_settings(C)->doublimit; // XXX
+ const float limit = RNA_float_get(op->ptr, "threshold");
float value = v_act->co[axis];
if (mode == 0)
@@ -3201,6 +3745,7 @@ void MESH_OT_select_axis(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
+ RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 93ebbbcf620..2b437c02aef 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -96,7 +96,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
}
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_ROOT, false,
+ smooth, SUBD_FALLOFF_INVSQUARE, false,
fractal, along_normal,
cuts,
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
@@ -134,19 +134,20 @@ void MESH_OT_subdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT,
"Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
- RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f, "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
+ RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, 1e6f, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f,
+ "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
}
/* -------------------------------------------------------------------- */
@@ -176,18 +177,18 @@ 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, INT_MAX, "Number of Cuts", "", 0, 64);
+ prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
"Interpolation", "Interpolation method");
- RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, FLT_MAX,
+ RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1e3f,
"Smoothness", "Smoothness factor", 0.0f, 2.0f);
/* profile-shape */
- RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -FLT_MAX, FLT_MAX,
- "Profile Factor", "", -2.0f, 2.0f);
+ RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -1e3f, 1e3f,
+ "Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f);
prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
@@ -289,7 +290,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "iterations", 2, 1, INT_MAX, "Iterations", "Number of times to unsubdivide", 1, 100);
+ RNA_def_int(ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
}
void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
@@ -313,6 +314,16 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
}
}
+
+/* Note, these values must match delete_mesh() event values */
+enum {
+ MESH_DELETE_VERT = 0,
+ MESH_DELETE_EDGE = 1,
+ MESH_DELETE_FACE = 2,
+ MESH_DELETE_EDGE_FACE = 3,
+ MESH_DELETE_ONLY_FACE = 4,
+};
+
static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
{
BKE_reportf(reports, RPT_INFO,
@@ -320,45 +331,38 @@ static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int to
totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
}
-/* Note, these values must match delete_mesh() event values */
-static EnumPropertyItem prop_mesh_delete_types[] = {
- {0, "VERT", 0, "Vertices", ""},
- {1, "EDGE", 0, "Edges", ""},
- {2, "FACE", 0, "Faces", ""},
- {3, "EDGE_FACE", 0, "Only Edges & Faces", ""},
- {4, "ONLY_FACE", 0, "Only Faces", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
static int edbm_delete_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- if (type == 0) {
- if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
- return OPERATOR_CANCELLED;
- }
- else if (type == 1) {
- if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
- return OPERATOR_CANCELLED;
- }
- else if (type == 2) {
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 3) {
- if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) /* Edges and Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 4) {
- //"Erase Only Faces";
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i",
- BM_ELEM_SELECT, DEL_ONLYFACES))
- {
- return OPERATOR_CANCELLED;
- }
+ switch (type) {
+ case MESH_DELETE_VERT:
+ if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE:
+ if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_FACE:
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE_FACE:
+ /* Edges and Faces */
+ if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_ONLY_FACE:
+ /* Only faces. */
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -370,6 +374,15 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
void MESH_OT_delete(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_mesh_delete_types[] = {
+ {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
+ {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
+ {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
+ {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
+ {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Delete";
ot->description = "Delete selected vertices, edges or faces";
@@ -385,7 +398,8 @@ void MESH_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT,
+ "Type", "Method used for deleting mesh data");
}
@@ -492,7 +506,7 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
+ if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
return OPERATOR_CANCELLED;
EDBM_update_generic(em, true, true);
@@ -1109,28 +1123,111 @@ static bool bm_vert_connect_select_history(BMesh *bm)
return false;
}
+/**
+ * Convert an edge selection to a temp vertex selection
+ * (which must be cleared after use as a path to connect).
+ */
+static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
+{
+ ListBase selected_orig = {NULL, NULL};
+ BMEditSelection *ese;
+ int edges_len = 0;
+ bool side = false;
+
+ /* first check all edges are OK */
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->htype == BM_EDGE) {
+ edges_len += 1;
+ }
+ else {
+ return false;
+ }
+ }
+ /* if this is a mixed selection, bail out! */
+ if (bm->totedgesel != edges_len) {
+ return false;
+ }
+
+ SWAP(ListBase, bm->selected, selected_orig);
+
+ /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
+ for (ese = selected_orig.first; ese; ese = ese->next) {
+ BMEdge *e_curr = (BMEdge *)ese->ele;
+ BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
+ BMLoop *l_curr;
+ BMLoop *l_prev;
+ BMVert *v;
+
+ if (e_prev) {
+ BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
+ if (f) {
+ if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
+ side = !side;
+ }
+ }
+ else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
+ side = !side;
+ }
+ }
+
+ v = (&e_curr->v1)[side];
+ if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
+ BM_select_history_store_notest(bm, v);
+ }
+
+ v = (&e_curr->v1)[!side];
+ if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
+ BM_select_history_store_head_notest(bm, v);
+ }
+
+ e_prev = e_curr;
+ }
+
+ *r_selected = bm->selected;
+ bm->selected = selected_orig;
+
+ return true;
+}
static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
bool is_pair = (em->bm->totvertsel == 2);
+ ListBase selected_orig = {NULL, NULL};
+ int retval;
/* when there is only 2 vertices, we can ignore selection order */
if (is_pair) {
return edbm_vert_connect_exec(C, op);
}
- if (bm_vert_connect_select_history(em->bm)) {
+ if (bm->selected.first) {
+ BMEditSelection *ese = bm->selected.first;
+ if (ese->htype == BM_EDGE) {
+ if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
+ SWAP(ListBase, bm->selected, selected_orig);
+ }
+ }
+ }
+
+ if (bm_vert_connect_select_history(bm)) {
EDBM_selectmode_flush(em);
EDBM_update_generic(em, true, true);
-
- return OPERATOR_FINISHED;
+ retval = OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
- return OPERATOR_CANCELLED;
+ retval = OPERATOR_CANCELLED;
}
+
+ if (!BLI_listbase_is_empty(&selected_orig)) {
+ BM_select_history_clear(bm);
+ bm->selected = selected_orig;
+ }
+
+ return retval;
}
void MESH_OT_vert_connect_path(wmOperatorType *ot)
@@ -1226,6 +1323,43 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
}
+static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+ const float fac = RNA_float_get(op->ptr, "factor");
+
+ if (!EDBM_op_callf(
+ em, op, "planar_faces faces=%hf iterations=%i factor=%f",
+ BM_ELEM_SELECT, repeat, fac))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_face_make_planar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Planar Faces";
+ ot->idname = "MESH_OT_face_make_planar";
+ ot->description = "Flatten selected faces";
+
+ /* api callbacks */
+ ot->exec = edbm_face_make_planar_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
+}
+
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
@@ -1460,7 +1594,7 @@ void MESH_OT_hide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1522,7 +1656,7 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+ RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
}
@@ -1609,9 +1743,9 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
- RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis");
- RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis");
- RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
+ RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
+ RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
+ RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
}
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
@@ -1686,16 +1820,16 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 200,
+ RNA_def_int(ot->srna, "repeat", 1, 1, 1000,
"Number of iterations to smooth the mesh", "", 1, 200);
- RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor", "", 0.0000001f, 1000.0f);
- RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor in border", "", 0.0000001f, 1000.0f);
- RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along X axis");
- RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along Y axis");
- RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along Z axis");
- RNA_def_boolean(ot->srna, "preserve_volume", 1, "Preserve Volume", "Apply volume preservation after smooth");
+ RNA_def_float(ot->srna, "lambda_factor", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor", "", 1e-7f, 1000.0f);
+ RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor in border", "", 1e-7f, 1000.0f);
+ RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
+ RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
+ RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
+ RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
}
/********************** Smooth/Solid Operators *************************/
@@ -1940,6 +2074,14 @@ void MESH_OT_colors_reverse(wmOperatorType *ot)
}
+enum {
+ MESH_MERGE_LAST = 1,
+ MESH_MERGE_CENTER = 3,
+ MESH_MERGE_CURSOR = 4,
+ MESH_MERGE_COLLAPSE = 5,
+ MESH_MERGE_FIRST = 6,
+};
+
static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
{
BMVert *mergevert;
@@ -2036,22 +2178,20 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
bool ok = false;
switch (type) {
- case 3:
+ case MESH_MERGE_CENTER:
ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
break;
- case 4:
+ case MESH_MERGE_CURSOR:
ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
break;
- case 1:
+ case MESH_MERGE_LAST:
ok = merge_firstlast(em, false, uvs, op);
break;
- case 6:
+ case MESH_MERGE_FIRST:
ok = merge_firstlast(em, true, uvs, op);
break;
- case 5:
- ok = true;
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
- ok = false;
+ case MESH_MERGE_COLLAPSE:
+ ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
break;
default:
BLI_assert(0);
@@ -2068,11 +2208,11 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
}
static EnumPropertyItem merge_type_items[] = {
- {6, "FIRST", 0, "At First", ""},
- {1, "LAST", 0, "At Last", ""},
- {3, "CENTER", 0, "At Center", ""},
- {4, "CURSOR", 0, "At Cursor", ""},
- {5, "COLLAPSE", 0, "Collapse", ""},
+ {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
+ {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
+ {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
+ {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
+ {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -2094,20 +2234,20 @@ static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),
((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
{
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
}
else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
}
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -2134,9 +2274,9 @@ void MESH_OT_merge(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
RNA_def_enum_funcs(ot->prop, merge_type_itemf);
- RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge");
+ RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
}
@@ -2212,9 +2352,9 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
- RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
}
@@ -2408,9 +2548,9 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
RNA_def_enum_funcs(prop, shape_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
- RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK);
+ RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
+ RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
}
static int edbm_solidify_exec(bContext *C, wmOperator *op)
@@ -2463,8 +2603,8 @@ void MESH_OT_solidify(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
- RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
}
/* ******************************************************************** */
@@ -2797,9 +2937,18 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
}
+
+/* *************** Operator: separate parts *************/
+
+enum {
+ MESH_SEPARATE_SELECTED = 0,
+ MESH_SEPARATE_MATERIAL = 1,
+ MESH_SEPARATE_LOOSE = 2,
+};
+
static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
{
Base *base_new;
@@ -3083,17 +3232,27 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
/* editmode separate */
- if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm);
- else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm);
- else if (type == 2) retval = mesh_separate_loose(bmain, scene, base, em->bm);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_SELECTED:
+ retval = mesh_separate_selected(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_MATERIAL:
+ retval = mesh_separate_material(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval = mesh_separate_loose(bmain, scene, base, em->bm);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval) {
EDBM_update_generic(em, true, true);
}
}
else {
- if (type == 0) {
+ if (type == MESH_SEPARATE_SELECTED) {
BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
return OPERATOR_CANCELLED;
}
@@ -3112,9 +3271,17 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
BM_mesh_bm_from_me(bm_old, me, false, false, 0);
- if (type == 1) retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
- else if (type == 2) retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_MATERIAL:
+ retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval_iter) {
BM_mesh_bm_to_me(bm_old, me, false);
@@ -3143,17 +3310,15 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-/* *************** Operator: separate parts *************/
-
-static EnumPropertyItem prop_separate_types[] = {
- {0, "SELECTED", 0, "Selection", ""},
- {1, "MATERIAL", 0, "By Material", ""},
- {2, "LOOSE", 0, "By loose parts", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
void MESH_OT_separate(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_separate_types[] = {
+ {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""},
+ {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""},
+ {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By loose parts", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Separate";
ot->description = "Separate selected geometry into a new mesh";
@@ -3167,7 +3332,7 @@ void MESH_OT_separate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
}
@@ -3460,11 +3625,11 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100);
+ prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of sides (zero disables)", 1, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100);
+ prop = RNA_def_int(ot->srna, "offset", 0, -1000, 1000, "Offset", "Number of sides (zero disables)", -100, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", "");
+ RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", "");
}
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
@@ -3502,7 +3667,8 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "sides", 4, 0, INT_MAX, "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
+ RNA_def_int(ot->srna, "sides", 4, 0, 1000,
+ "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
}
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
@@ -3622,9 +3788,10 @@ void MESH_OT_poke(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED, "Poke Center", "Poke Face Center Calculation");
+ RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED,
+ "Poke Center", "Poke Face Center Calculation");
}
/********************** Quad/Tri Operators *************************/
@@ -3678,19 +3845,45 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int dosharp, douvs, dovcols, domaterials;
- const float limit = RNA_float_get(op->ptr, "limit");
+ bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
+ float angle_face_threshold, angle_shape_threshold;
+ PropertyRNA *prop;
+
+ /* When joining exactly 2 faces, no limit.
+ * this is useful for one off joins while editing. */
+ prop = RNA_struct_find_property(op->ptr, "face_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_face_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_face_threshold = RNA_property_float_get(op->ptr, prop);
+ }
- dosharp = RNA_boolean_get(op->ptr, "sharp");
- douvs = RNA_boolean_get(op->ptr, "uvs");
- dovcols = RNA_boolean_get(op->ptr, "vcols");
- domaterials = RNA_boolean_get(op->ptr, "materials");
+ prop = RNA_struct_find_property(op->ptr, "shape_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_shape_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ do_seam = RNA_boolean_get(op->ptr, "seam");
+ do_sharp = RNA_boolean_get(op->ptr, "sharp");
+ do_uvs = RNA_boolean_get(op->ptr, "uvs");
+ do_vcols = RNA_boolean_get(op->ptr, "vcols");
+ do_materials = RNA_boolean_get(op->ptr, "materials");
if (!EDBM_op_call_and_selectf(
em, op,
"faces.out", true,
- "join_triangles faces=%hf limit=%f cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
- BM_ELEM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
+ "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
+ BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
+ do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
return OPERATOR_CANCELLED;
}
@@ -3704,14 +3897,21 @@ static void join_triangle_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
- "Max Angle", "Angle Limit", 0.0f, DEG2RADF(180.0f));
+ prop = RNA_def_float_rotation(
+ ot->srna, "face_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Face Angle", "Face angle limit", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(40.0f));
+
+ prop = RNA_def_float_rotation(
+ ot->srna, "shape_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Shape Angle", "Shape angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(40.0f));
- RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
- RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
- RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
- RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
+ RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", "");
+ RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", "");
+ RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", "");
+ RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", "");
}
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
@@ -3747,12 +3947,12 @@ static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int fl
}
static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split",
+ RNA_def_boolean(ot->srna, "use_face_split", false, "Face Split",
"Split off face corners to maintain surrounding geometry");
}
static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary",
+ RNA_def_boolean(ot->srna, "use_boundary_tear", false, "Tear Boundary",
"Split off face corners instead of merging faces");
}
@@ -3986,9 +4186,9 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
"Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
- RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries",
+ RNA_def_boolean(ot->srna, "use_dissolve_boundaries", false, "All Boundaries",
"Dissolve all vertices inbetween face boundaries");
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, 0, "Delimit",
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit",
"Delimit dissolve operation");
}
@@ -4032,8 +4232,8 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
}
@@ -4071,6 +4271,10 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+ }
+
EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
@@ -4710,8 +4914,9 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Type of re-ordering operation to apply");
- RNA_def_enum_flag(ot->srna, "elements", elem_items, 0, "Elements",
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, SRT_VIEW_ZAXIS,
+ "Type", "Type of re-ordering operation to apply");
+ RNA_def_enum_flag(ot->srna, "elements", elem_items, BM_VERT, "Elements",
"Which elements to affect (vertices, edges and/or faces)");
RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect");
RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
@@ -4786,10 +4991,16 @@ void MESH_OT_noise(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
}
+enum {
+ MESH_BRIDGELOOP_SINGLE = 0,
+ MESH_BRIDGELOOP_CLOSED = 1,
+ MESH_BRIDGELOOP_PAIRS = 2,
+};
+
static int edbm_bridge_tag_boundary_edges(BMesh *bm)
{
/* tags boundary edges from a face selection */
@@ -4838,8 +5049,8 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- const bool use_pairs = (type == 2);
- const bool use_cyclic = (type == 1);
+ const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
+ const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
@@ -4937,9 +5148,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
- {0, "SINGLE", 0, "Open Loop", ""},
- {1, "CLOSED", 0, "Closed Loop", ""},
- {2, "PAIRS", 0, "Loop Pairs", ""},
+ {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""},
+ {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""},
+ {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4955,7 +5166,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0,
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, MESH_BRIDGELOOP_SINGLE,
"Connect Loops", "Method of bridging multiple loops");
RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
@@ -5016,19 +5227,73 @@ void MESH_OT_wireframe(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
- RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, FLT_MAX, "Offset", "", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
- prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, FLT_MAX, "Crease weight", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
+ prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
}
+static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMOperator bmop;
+ const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
+
+ EDBM_op_init(
+ em, &bmop, op,
+ "offset_edgeloops edges=%he use_cap_endpoint=%b",
+ BM_ELEM_SELECT, use_cap_endpoint);
+
+ BMO_op_exec(em->bm, &bmop);
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state */
+ if (em->selectmode == SCE_SELECT_FACE) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ EDBM_selectmode_to_scene(C);
+ }
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+ }
+}
+
+void MESH_OT_offset_edge_loops(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Offset Edge Loop";
+ ot->idname = "MESH_OT_offset_edge_loops";
+ ot->description = "Create offset edge loop from the current selection";
+
+ /* api callbacks */
+ ot->exec = edbm_offset_edgeloop_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
+}
+
#ifdef WITH_BULLET
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
{
@@ -5072,11 +5337,16 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Merge adjacent triangles */
if (RNA_boolean_get(op->ptr, "join_triangles")) {
- if (!EDBM_op_call_and_selectf(em, op,
- "faces.out", true,
- "join_triangles faces=%S limit=%f",
- &bmop, "geom.out",
- RNA_float_get(op->ptr, "limit")))
+ float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
+ float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%S "
+ "angle_face_threshold=%f angle_shape_threshold=%f",
+ &bmop, "geom.out",
+ angle_face_threshold, angle_shape_threshold))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
@@ -5172,7 +5442,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Threshold", "", 0.00001, 0.1);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
}
static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
@@ -5296,8 +5566,8 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.05, 0.0, 10.0, "Threshold", "", 0.0001, 1.0);
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
}
@@ -5364,7 +5634,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -5428,7 +5698,7 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 86cd75eed7a..d521b2c01e5 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -37,6 +37,8 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
+#include "BLI_buffer.h"
+#include "BLI_kdtree.h"
#include "BLI_listbase.h"
#include "BKE_DerivedMesh.h"
@@ -613,7 +615,9 @@ void undo_push_mesh(bContext *C, const char *name)
/**
* Return a new UVVertMap from the editmesh
*/
-UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2])
+UvVertMap *BM_uv_vert_map_create(
+ BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding)
{
BMVert *ev;
BMFace *efa;
@@ -625,11 +629,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
/* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
unsigned int a;
- int totverts, i, totuv;
+ int totverts, i, totuv, totfaces;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ bool *winding = NULL;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
@@ -650,35 +657,46 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
+ if (use_winding) {
+ winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
+ }
if (!vmap->vert || !vmap->buf) {
BKE_mesh_uv_vert_map_free(vmap);
return NULL;
}
- a = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- i = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ }
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->tfindex = i;
buf->f = a;
buf->separate = 0;
buf->next = vmap->vert[BM_elem_index_get(l->v)];
vmap->vert[BM_elem_index_get(l->v)] = buf;
-
buf++;
- i++;
+
+ if (use_winding) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+ }
}
- }
- a++;
+ if (use_winding) {
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
+ }
+ }
}
/* sort individual uvs for each vert */
- a = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
UvMapVert *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -710,7 +728,9 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1]) {
+ if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
+ (!use_winding || winding[iterv->f] == winding[v->f]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -727,9 +747,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
}
vmap->vert[a] = newvlist;
- a++;
}
+ if (use_winding) {
+ MEM_freeN(winding);
+ }
+
+ BLI_buffer_free(&tf_uv_buf);
+
return vmap;
}
@@ -743,7 +768,9 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
/* A specialized vert map used by stitch operator */
-UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const bool do_islands)
+UvElementMap *BM_uv_element_map_create(
+ BMesh *bm,
+ const bool selected, const bool use_winding, const bool do_islands)
{
BMVert *ev;
BMFace *efa;
@@ -752,29 +779,20 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
/* vars from original func */
UvElementMap *element_map;
UvElement *buf;
- UvElement *islandbuf;
- /* island number for faces */
- int *island_number;
+ bool *winding;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
MLoopUV *luv;
- int totverts, i, totuv, j, nislands = 0, islandbufsize = 0;
-
- unsigned int *map;
- BMFace **stack;
- int stacksize = 0;
+ int totverts, totfaces, i, totuv, j;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
- island_number = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_number_face");
- if (!island_number) {
- return NULL;
- }
-
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
@@ -783,28 +801,31 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
if (totuv == 0) {
- MEM_freeN(island_number);
return NULL;
}
+
element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
- if (!element_map) {
- MEM_freeN(island_number);
- return NULL;
- }
element_map->totalUVs = totuv;
element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts");
buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement");
- if (!element_map->vert || !element_map->buf) {
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- return NULL;
+ if (use_winding) {
+ winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
}
- j = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- island_number[j++] = INVALID_ISLAND;
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
+
+ if (use_winding) {
+ winding[j] = false;
+ }
+
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ }
+
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->l = l;
buf->separate = 0;
@@ -814,14 +835,22 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
buf->next = element_map->vert[BM_elem_index_get(l->v)];
element_map->vert[BM_elem_index_get(l->v)] = buf;
+ if (use_winding) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+ }
+
buf++;
}
+
+ if (use_winding) {
+ winding[j] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
+ }
}
}
/* sort individual uvs for each vert */
- i = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
UvElement *newvlist = NULL, *vlist = element_map->vert[i];
UvElement *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -848,7 +877,9 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT) {
+ if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT &&
+ (!use_winding || winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -865,14 +896,28 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->vert[i] = newvlist;
- i++;
+ }
+
+ if (use_winding) {
+ MEM_freeN(winding);
}
if (do_islands) {
+ unsigned int *map;
+ BMFace **stack;
+ int stacksize = 0;
+ UvElement *islandbuf;
+ /* island number for faces */
+ int *island_number = NULL;
+
+ int nislands = 0, islandbufsize = 0;
+
/* map holds the map from current vmap->buf to the new, sorted map */
map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
+ island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
+ copy_vn_i(island_number, totfaces, INVALID_ISLAND);
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
for (i = 0; i < totuv; i++) {
@@ -921,6 +966,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
}
+ MEM_freeN(island_number);
+
/* remap */
for (i = 0; i < bm->totvert; i++) {
/* important since we may do selection only. Some of these may be NULL */
@@ -929,14 +976,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices");
- if (!element_map->islandIndices) {
- MEM_freeN(islandbuf);
- MEM_freeN(stack);
- MEM_freeN(map);
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- }
-
j = 0;
for (i = 0; i < totuv; i++) {
UvElement *element = element_map->buf[i].next;
@@ -958,7 +997,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
MEM_freeN(stack);
MEM_freeN(map);
}
- MEM_freeN(island_number);
+
+ BLI_buffer_free(&tf_uv_buf);
return element_map;
}
@@ -1036,26 +1076,19 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
}
/**
- * [note: I've decided to use ideasman's code for non-editmode stuff, but since
- * it has a big "not for editmode!" disclaimer, I'm going to keep what I have here
- * - joeedh]
- *
- * x-mirror editing api. usage:
+ * Mirror editing API, usage:
*
- * EDBM_verts_mirror_cache_begin(em);
- * ...
- * ...
- * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- * mirrorv = EDBM_verts_mirror_get(em, v);
- * }
- * ...
- * ...
- * EDBM_verts_mirror_cache_end(em);
+ * \code{.c}
+ * EDBM_verts_mirror_cache_begin(em, ...);
*
- * \param use_self Allow a vertex to reference its self.
- * \param use_select Only cache selected verts.
+ * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ * v_mirror = EDBM_verts_mirror_get(em, v);
+ * e_mirror = EDBM_verts_mirror_get_edge(em, e);
+ * f_mirror = EDBM_verts_mirror_get_face(em, f);
+ * }
*
- * \note why do we only allow x axis mirror editing?
+ * EDBM_verts_mirror_cache_end(em);
+ * \endcode
*/
/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
@@ -1080,9 +1113,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
BMVert *v;
int cd_vmirr_offset;
int i;
+ const float maxdist_sq = SQUARE(maxdist);
/* one or the other is used depending if topo is enabled */
- struct BMBVHTree *tree = NULL;
+ KDTree *tree = NULL;
MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
BM_mesh_elem_table_ensure(bm, BM_VERT);
@@ -1107,7 +1141,11 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, true);
}
else {
- tree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ tree = BLI_kdtree_new(bm->totvert);
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_insert(tree, i, v->co);
+ }
+ BLI_kdtree_balance(tree);
}
#define VERT_INTPTR(_v, _i) r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset);
@@ -1127,10 +1165,19 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
}
else {
+ int i_mirr;
float co[3];
copy_v3_v3(co, v->co);
co[axis] *= -1.0f;
- v_mirr = BKE_bmbvh_find_vert_closest(tree, co, maxdist);
+
+ v_mirr = NULL;
+ i_mirr = BLI_kdtree_find_nearest(tree, co, NULL);
+ if (i_mirr != -1) {
+ BMVert *v_test = BM_vert_at_index(bm, i_mirr);
+ if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
+ v_mirr = v_test;
+ }
+ }
}
if (v_mirr && (use_self || (v_mirr != v))) {
@@ -1152,7 +1199,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_free(&mesh_topo_store);
}
else {
- BKE_bmbvh_free(tree);
+ BLI_kdtree_free(tree);
}
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 86991d7dfeb..a2054a5f43c 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -429,7 +429,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set)
/* copy data from active vertex color layer */
if (layernum) {
const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL);
- BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum, layernum_dst);
+ BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
@@ -748,7 +748,7 @@ static int mesh_customdata_clear_exec__internal(bContext *C,
}
/* Clear Mask */
-static int mesh_customdata_clear_mask_poll(bContext *C)
+static int mesh_customdata_mask_clear_poll(bContext *C)
{
Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
@@ -772,7 +772,7 @@ static int mesh_customdata_clear_mask_poll(bContext *C)
}
return false;
}
-static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK);
int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK);
@@ -787,24 +787,27 @@ static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
}
}
-void MESH_OT_customdata_clear_mask(wmOperatorType *ot)
+void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Sculpt-Mask Data";
- ot->idname = "MESH_OT_customdata_clear_mask";
+ ot->idname = "MESH_OT_customdata_mask_clear";
ot->description = "Clear vertex sculpt masking data from the mesh";
/* api callbacks */
- ot->exec = mesh_customdata_clear_mask_exec;
- ot->poll = mesh_customdata_clear_mask_poll;
+ ot->exec = mesh_customdata_mask_clear_exec;
+ ot->poll = mesh_customdata_mask_clear_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Clear Skin */
-static int mesh_customdata_clear_skin_poll(bContext *C)
+/**
+ * Clear Skin
+ * \return -1 invalid state, 0 no skin, 1 has skin.
+ */
+static int mesh_customdata_skin_state(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -812,28 +815,65 @@ static int mesh_customdata_clear_skin_poll(bContext *C)
Mesh *me = ob->data;
if (me->id.lib == NULL) {
CustomData *data = GET_CD_DATA(me, vdata);
- if (CustomData_has_layer(data, CD_MVERT_SKIN)) {
- return true;
- }
+ return CustomData_has_layer(data, CD_MVERT_SKIN);
}
}
- return false;
+ return -1;
}
-static int mesh_customdata_clear_skin_exec(bContext *C, wmOperator *UNUSED(op))
+
+static int mesh_customdata_skin_add_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 0);
+}
+
+static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ BKE_mesh_ensure_skin_customdata(me);
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_customdata_skin_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Skin Data";
+ ot->idname = "MESH_OT_customdata_skin_add";
+ ot->description = "Add a vertex skin layer";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_skin_add_exec;
+ ot->poll = mesh_customdata_skin_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int mesh_customdata_skin_clear_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 1);
+}
+
+static int mesh_customdata_skin_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_MVERT_SKIN);
}
-void MESH_OT_customdata_clear_skin(wmOperatorType *ot)
+void MESH_OT_customdata_skin_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Skin Data";
- ot->idname = "MESH_OT_customdata_clear_skin";
+ ot->idname = "MESH_OT_customdata_skin_clear";
ot->description = "Clear vertex skin layer";
/* api callbacks */
- ot->exec = mesh_customdata_clear_skin_exec;
- ot->poll = mesh_customdata_clear_skin_poll;
+ ot->exec = mesh_customdata_skin_clear_exec;
+ ot->poll = mesh_customdata_skin_clear_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 8611872a1a0..c56465f570a 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -34,14 +34,9 @@
#ifndef __MESH_INTERN_H__
#define __MESH_INTERN_H__
-struct BMEdge;
struct BMEditMesh;
-struct BMFace;
-struct BMHeader;
struct BMOperator;
-struct BMesh;
struct EnumPropertyItem;
-struct ViewContext;
struct bContext;
struct wmKeyConfig;
struct wmKeyMap;
@@ -178,8 +173,10 @@ void MESH_OT_vert_connect(struct wmOperatorType *ot);
void MESH_OT_vert_connect_path(struct wmOperatorType *ot);
void MESH_OT_vert_connect_concave(struct wmOperatorType *ot);
void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot);
+void MESH_OT_face_make_planar(struct wmOperatorType *ot);
void MESH_OT_edge_split(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
+void MESH_OT_offset_edge_loops(struct wmOperatorType *ot);
void MESH_OT_wireframe(struct wmOperatorType *ot);
void MESH_OT_convex_hull(struct wmOperatorType *ot);
void MESH_OT_symmetrize(struct wmOperatorType *ot);
@@ -237,8 +234,9 @@ void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
/* no create_mask yet */
-void MESH_OT_customdata_clear_mask(struct wmOperatorType *ot);
-void MESH_OT_customdata_clear_skin(struct wmOperatorType *ot);
+void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 440ab14dacd..1c36826b882 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -84,7 +84,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
for (oblink = obs; oblink; oblink = oblink->next) {
ob = (Object *) oblink->link;
dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
- BLI_linklist_append(&dms, (void *)dm);
+ BLI_linklist_prepend(&dms, dm);
nverts += dm->getNumVerts(dm);
nfaces = dm->getNumTessFaces(dm);
@@ -325,7 +325,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
if (createob) {
/* create new object */
- obedit = ED_object_add_type(C, OB_MESH, co, rot, false, lay);
+ obedit = ED_object_add_type(C, OB_MESH, "Navmesh", co, rot, false, lay);
}
else {
obedit = base->object;
@@ -429,7 +429,6 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
obedit->gameflag &= ~OB_COLLISION;
obedit->gameflag |= OB_NAVMESH;
obedit->body_type = OB_BODY_TYPE_NAVMESH;
- rename_id((ID *)obedit, "Navmesh");
}
BKE_mesh_ensure_navmesh(obedit->data);
@@ -452,7 +451,7 @@ static int navmesh_create_exec(bContext *C, wmOperator *op)
}
}
else {
- BLI_linklist_append(&obs, (void *)base->object);
+ BLI_linklist_prepend(&obs, base->object);
}
}
}
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 2855af063c0..9718e63f012 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -151,8 +151,9 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
WM_operatortype_append(MESH_OT_vertex_color_remove);
- WM_operatortype_append(MESH_OT_customdata_clear_mask);
- WM_operatortype_append(MESH_OT_customdata_clear_skin);
+ WM_operatortype_append(MESH_OT_customdata_mask_clear);
+ WM_operatortype_append(MESH_OT_customdata_skin_add);
+ WM_operatortype_append(MESH_OT_customdata_skin_clear);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
WM_operatortype_append(MESH_OT_drop_named_image);
@@ -166,6 +167,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_vert_connect_path);
WM_operatortype_append(MESH_OT_vert_connect_concave);
WM_operatortype_append(MESH_OT_vert_connect_nonplanar);
+ WM_operatortype_append(MESH_OT_face_make_planar);
WM_operatortype_append(MESH_OT_knife_tool);
WM_operatortype_append(MESH_OT_knife_project);
@@ -175,6 +177,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_bridge_edge_loops);
WM_operatortype_append(MESH_OT_inset);
+ WM_operatortype_append(MESH_OT_offset_edge_loops);
WM_operatortype_append(MESH_OT_intersect);
WM_operatortype_append(MESH_OT_face_split_by_edges);
WM_operatortype_append(MESH_OT_poke);
@@ -223,6 +226,13 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
RNA_boolean_set(otmacro->ptr, "release_confirm", false);
+ ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", "Offset Edge Slide", "Offset edge loop slide",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
+ RNA_boolean_set(otmacro->ptr, "release_confirm", false);
+ RNA_boolean_set(otmacro->ptr, "single_side", true);
+
ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", "Duplicate mesh and move",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
@@ -300,7 +310,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Mesh", 0, 0);
keymap->poll = ED_operator_editmesh;
- WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_offset_edge_loops_slide", RKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
WM_keymap_add_item(keymap, "MESH_OT_inset", IKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "MESH_OT_poke", PKEY, KM_PRESS, KM_ALT, 0);
kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index f85bb23ffc1..2491685161c 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1025,7 +1025,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
ED_mesh_mirror_spatial_table(ob, em, NULL, 'e');
- fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface, false);
+ fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
for (a = 0, mf = mface; a < me->totface; a++, mf++)
BLI_ghash_insert(fhash, mf, mf);
@@ -1082,11 +1082,11 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
* on an edge in the backbuf, we can still select a face */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totpoly)
@@ -1248,11 +1248,11 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
* on an face in the backbuf, we can still select a vert */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totvert)
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 24cac5b9b70..42eda235276 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -404,7 +404,8 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
+ RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
WM_operator_properties_select_action_simple(ot, SEL_SELECT);
}
@@ -532,7 +533,7 @@ void MBALL_OT_hide_metaelems(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
/***************************** Unhide operator *****************************/
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 99b351561c7..075e382f628 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -57,6 +57,7 @@
#include "BLF_translation.h"
+#include "BKE_action.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
@@ -262,7 +263,7 @@ void ED_object_add_unit_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
RNA_def_property_subtype(prop, PROP_DISTANCE);
}
@@ -280,11 +281,12 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
- prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
- "Location for the newly added object", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Location", "Location for the newly added object", -1000.0f, 1000.0f);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -FLT_MAX, FLT_MAX, "Rotation",
- "Rotation for the newly added object", (float)-M_PI * 2.0f, (float)M_PI * 2.0f);
+ prop = RNA_def_float_rotation(ot->srna, "rotation", 3, NULL, -OBJECT_ADD_SIZE_MAXF, OBJECT_ADD_SIZE_MAXF,
+ "Rotation", "Rotation for the newly added object",
+ DEG2RADF(-360.0f), DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
@@ -394,8 +396,11 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
/* For object add primitive operators.
* Do not call undo push in this function (users of this function have to). */
-Object *ED_object_add_type(bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer)
+Object *ED_object_add_type(
+ bContext *C,
+ int type, const char *name,
+ const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -406,7 +411,7 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
/* deselects all, sets scene->basact */
- ob = BKE_object_add(bmain, scene, type);
+ ob = BKE_object_add(bmain, scene, type, name);
BASACT->lay = ob->lay = layer;
/* editor level activate, notifiers */
ED_base_object_activate(C, BASACT);
@@ -447,7 +452,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
radius = RNA_float_get(op->ptr, "radius");
- ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer);
+ ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, layer);
if (ob->type == OB_LATTICE) {
/* lattice is a special case!
@@ -504,9 +509,9 @@ static int effector_add_exec(bContext *C, wmOperator *op)
if (type == PFIELD_GUIDE) {
Curve *cu;
- ob = ED_object_add_type(C, OB_CURVE, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide");
+ ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, layer);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide"));
cu = ob->data;
cu->flag |= CU_PATH | CU_3D;
ED_object_editmode_enter(C, 0);
@@ -516,9 +521,9 @@ static int effector_add_exec(bContext *C, wmOperator *op)
ED_object_editmode_exit(C, EM_FREEDATA);
}
else {
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field");
+ ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, layer);
BKE_object_obdata_size_init(ob, dia);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field"));
if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX))
ob->empty_drawtype = OB_SINGLE_ARROW;
}
@@ -569,7 +574,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_CAMERA, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, layer);
if (v3d) {
if (v3d->camera == NULL)
@@ -626,7 +631,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (obedit == NULL || obedit->type != OB_MBALL) {
- obedit = ED_object_add_type(C, OB_MBALL, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, layer);
newob = true;
}
else {
@@ -685,7 +690,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
if (obedit && obedit->type == OB_FONT)
return OPERATOR_CANCELLED;
- obedit = ED_object_add_type(C, OB_FONT, loc, rot, enter_editmode, layer);
+ obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, layer);
BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius"));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
@@ -729,7 +734,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
- obedit = ED_object_add_type(C, OB_ARMATURE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, layer);
ED_object_editmode_enter(C, 0);
newob = true;
}
@@ -786,7 +791,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer);
BKE_object_empty_draw_type_set(ob, type);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
@@ -846,7 +851,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, NULL, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, layer);
/* add under the mouse */
ED_object_location_from_view(C, ob->loc);
@@ -916,13 +921,11 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_LAMP, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
la = (Lamp *)ob->data;
la->type = type;
- rename_id(&ob->id, get_lamp_defname(type));
- rename_id(&la->id, get_lamp_defname(type));
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_node_shader_default(C, &la->id);
@@ -988,8 +991,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
if (group) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -1044,14 +1046,14 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, layer);
/* to make it easier to start using this immediately in NLA, a default sound clip is created
* ready to be moved around to retime the sound and/or make new sound clips
*/
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_id_add_animdata(&ob->id);
+ AnimData *adt = BKE_animdata_add_id(&ob->id);
NlaTrack *nlt = add_nlatrack(adt, NULL);
NlaStrip *strip = add_nla_soundstrip(scene, ob->data);
strip->start = CFRA;
@@ -1358,7 +1360,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_free_animdata(&ob->id);
+ BKE_animdata_free(&ob->id);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1976,7 +1978,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->id);
+ BKE_animdata_copy_id_action(&obn->id);
}
if (dupflag & USER_DUP_MAT) {
@@ -1989,7 +1991,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
id->us--;
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->mat[a]->id);
+ BKE_animdata_copy_id_action(&obn->mat[a]->id);
}
}
}
@@ -2004,7 +2006,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
psys->part = BKE_particlesettings_copy(psys->part);
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&psys->part->id);
+ BKE_animdata_copy_id_action(&psys->part->id);
}
id->us--;
@@ -2082,7 +2084,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
case OB_ARMATURE:
DAG_id_tag_update(&obn->id, OB_RECALC_DATA);
if (obn->pose)
- obn->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, obn->pose);
if (dupflag & USER_DUP_ARM) {
ID_NEW_US2(obn->data)
else {
@@ -2132,9 +2134,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ACT) {
bActuator *act;
- BKE_copy_animdata_id_action((ID *)obn->data);
+ BKE_animdata_copy_id_action((ID *)obn->data);
if (key) {
- BKE_copy_animdata_id_action((ID *)key);
+ BKE_animdata_copy_id_action((ID *)key);
}
/* Update the duplicated action in the action actuators */
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 97cb45daae3..b382fbafcfd 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -574,6 +574,7 @@ static int bake(
float *result = NULL;
BakePixel *pixel_array_low = NULL;
+ BakePixel *pixel_array_high = NULL;
const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
const bool is_noncolor = is_noncolor_pass(pass_type);
@@ -682,10 +683,13 @@ static int bake(
}
pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
+ pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
/* get the mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_low);
+ BKE_mesh_tessface_ensure(me_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -700,7 +704,9 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
if (me_low->totface != me_cage->totface) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
@@ -732,7 +738,9 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -749,8 +757,6 @@ static int bake(
/* initialize highpoly_data */
highpoly[i].ob = ob_iter;
highpoly[i].restrict_flag = ob_iter->restrictflag;
- highpoly[i].pixel_array = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
-
/* triangulating so BVH returns the primitive_id that will be used for rendering */
highpoly[i].tri_mod = ED_object_modifier_add(
@@ -760,18 +766,16 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 1, 0);
+ highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
+ BKE_mesh_split_faces(highpoly[i].me);
+ BKE_mesh_tessface_ensure(highpoly[i].me);
/* lowpoly to highpoly transformation matrix */
copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);
- /* rotation */
- normalize_m4_m4(highpoly[i].rotmat, highpoly[i].imat);
- zero_v3(highpoly[i].rotmat[3]);
- if (is_negative_m4(highpoly[i].rotmat))
- negate_mat3_m4(highpoly[i].rotmat);
+ highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat);
i++;
}
@@ -782,7 +786,7 @@ static int bake(
/* populate the pixel arrays with the corresponding face data for each high poly object */
if (!RE_bake_pixels_populate_from_objects(
- me_low, pixel_array_low, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
+ me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage))
{
BKE_report(reports, RPT_ERROR, "Error handling selected objects");
@@ -791,8 +795,8 @@ static int bake(
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
- ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
- depth, pass_type, result);
+ ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
+ num_pixels, depth, pass_type, result);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
goto cage_cleanup;
@@ -818,7 +822,7 @@ cage_cleanup:
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
+ ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result);
}
else {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -867,7 +871,9 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_nores);
+ BKE_mesh_tessface_ensure(me_nores);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -919,7 +925,7 @@ cage_cleanup:
BakeData *bake = &scene->r.bake;
char name[FILE_MAX];
- BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
+ BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
@@ -980,9 +986,6 @@ cleanup:
for (i = 0; i < tot_highpoly; i++) {
highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;
- if (highpoly[i].pixel_array)
- MEM_freeN(highpoly[i].pixel_array);
-
if (highpoly[i].tri_mod)
ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);
@@ -1000,6 +1003,9 @@ cleanup:
if (pixel_array_low)
MEM_freeN(pixel_array_low);
+ if (pixel_array_high)
+ MEM_freeN(pixel_array_high);
+
if (bake_images.data)
MEM_freeN(bake_images.data);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 231d23b481d..e14674ef517 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -226,7 +226,7 @@ static void update_pyconstraint_cb(void *arg1, void *arg2)
/* helper function for add_constriant - sets the last target for the active constraint */
static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
@@ -260,17 +260,221 @@ static void set_constraint_nth_target(bConstraint *con, Object *target, const ch
/* ------------- Constraint Sanity Testing ------------------- */
-/* checks validity of object pointers, and NULLs,
- * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
- */
-static void test_constraints(Object *owner, bPoseChannel *pchan)
+static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+ bool check_targets = true;
+
+ /* clear disabled-flag first */
+ con->flag &= ~CONSTRAINT_DISABLE;
+
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+
+ /* bad: we need a separate set of checks here as poletarget is
+ * optional... otherwise poletarget must exist too or else
+ * the constraint is deemed invalid
+ */
+ /* default IK check ... */
+ if (BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ if (data->poletar) {
+ if (BKE_object_exists_check(data->poletar) == 0) {
+ data->poletar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->poletar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ /* ... can be overwritten here */
+ BIK_test_constraint(owner, con);
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_PIVOT) {
+ bPivotConstraint *data = con->data;
+
+ /* target doesn't have to exist, but if it is non-null, it must exist! */
+ if (data->tar && BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data;
+
+ /* validate action */
+ if (data->act == NULL) {
+ /* must have action */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->act->idroot != ID_OB) {
+ /* only object-rooted actions can be used */
+ data->act = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->upflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->upflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRACKTO) {
+ bTrackToConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->reserved2 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->reserved2 + 3 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_LOCKTRACK) {
+ bLockTrackConstraint *data = con->data;
+
+ if (data->lockflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->lockflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ bSplineIKConstraint *data = con->data;
+
+ /* if the number of points does not match the amount required by the chain length,
+ * free the points array and request a rebind...
+ */
+ if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
+ /* free the points array */
+ if (data->points) {
+ MEM_freeN(data->points);
+ data->points = NULL;
+ }
+
+ /* clear the bound flag, forcing a rebind next time this is evaluated */
+ data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
+ if (data->clip != NULL && data->track[0]) {
+ MovieTracking *tracking = &data->clip->tracking;
+ MovieTrackingObject *tracking_object;
+
+ if (data->object[0])
+ tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ else
+ tracking_object = BKE_tracking_object_get_camera(tracking);
+
+ if (!tracking_object) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
+ bCameraSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+
+ /* Check targets for constraints */
+ if (check_targets && cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ /* disable and clear constraints targets that are incorrect */
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* general validity checks (for those constraints that need this) */
+ if (BKE_object_exists_check(ct->tar) == 0) {
+ /* object doesn't exist, but constraint requires target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (ct->tar == owner) {
+ if (type == CONSTRAINT_OBTYPE_BONE) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
+ /* bone must exist in armature... */
+ /* TODO: clear subtarget? */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (STREQ(pchan->name, ct->subtarget)) {
+ /* cannot target self */
+ ct->subtarget[0] = '\0';
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ /* cannot use self as target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* target checks for specific constraints */
+ if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
+ if (ct->tar) {
+ if (ct->tar->type != OB_CURVE) {
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ Curve *cu = ct->tar->data;
+
+ /* auto-set 'Path' setting on curve so this works */
+ cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+
+ /* free any temporary targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+}
+
+static int constraint_type_get(Object *owner, bPoseChannel *pchan)
{
- bConstraint *curcon;
- ListBase *conlist = NULL;
int type;
-
- if (owner == NULL) return;
-
/* Check parents */
if (pchan) {
switch (owner->type) {
@@ -284,7 +488,22 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
}
else
type = CONSTRAINT_OBTYPE_OBJECT;
+ return type;
+}
+
+/* checks validity of object pointers, and NULLs,
+ * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
+ */
+static void test_constraints(Object *owner, bPoseChannel *pchan)
+{
+ bConstraint *curcon;
+ ListBase *conlist = NULL;
+ int type;
+ if (owner == NULL) return;
+
+ type = constraint_type_get(owner, pchan);
+
/* Get the constraint list for this object */
switch (type) {
case CONSTRAINT_OBTYPE_OBJECT:
@@ -298,213 +517,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
/* Check all constraints - is constraint valid? */
if (conlist) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* clear disabled-flag first */
- curcon->flag &= ~CONSTRAINT_DISABLE;
-
- if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = curcon->data;
-
- /* bad: we need a separate set of checks here as poletarget is
- * optional... otherwise poletarget must exist too or else
- * the constraint is deemed invalid
- */
- /* default IK check ... */
- if (BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- if (data->poletar) {
- if (BKE_object_exists_check(data->poletar) == 0) {
- data->poletar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->poletar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- /* ... can be overwritten here */
- BIK_test_constraint(owner, curcon);
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_PIVOT) {
- bPivotConstraint *data = curcon->data;
-
- /* target doesn't have to exist, but if it is non-null, it must exist! */
- if (data->tar && BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = curcon->data;
-
- /* validate action */
- if (data->act == NULL) {
- /* must have action */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->act->idroot != ID_OB) {
- /* only object-rooted actions can be used */
- data->act = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWPATH) {
- bFollowPathConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->upflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->upflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_TRACKTO) {
- bTrackToConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->reserved2 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->reserved2 + 3 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_LOCKTRACK) {
- bLockTrackConstraint *data = curcon->data;
-
- if (data->lockflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->lockflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_SPLINEIK) {
- bSplineIKConstraint *data = curcon->data;
-
- /* if the number of points does not match the amount required by the chain length,
- * free the points array and request a rebind...
- */
- if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
- /* free the points array */
- if (data->points) {
- MEM_freeN(data->points);
- data->points = NULL;
- }
-
- /* clear the bound flag, forcing a rebind next time this is evaluated */
- data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
- if (data->clip != NULL && data->track[0]) {
- MovieTracking *tracking = &data->clip->tracking;
- MovieTrackingObject *tracking_object;
-
- if (data->object[0])
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
- else
- tracking_object = BKE_tracking_object_get_camera(tracking);
-
- if (!tracking_object) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
-
- /* Check targets for constraints */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- /* disable and clear constraints targets that are incorrect */
- for (ct = targets.first; ct; ct = ct->next) {
- /* general validity checks (for those constraints that need this) */
- if (BKE_object_exists_check(ct->tar) == 0) {
- /* object doesn't exist, but constraint requires target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (ct->tar == owner) {
- if (type == CONSTRAINT_OBTYPE_BONE) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
- /* bone must exist in armature... */
- /* TODO: clear subtarget? */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (STREQ(pchan->name, ct->subtarget)) {
- /* cannot target self */
- ct->subtarget[0] = '\0';
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- /* cannot use self as target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* target checks for specific constraints */
- if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
- if (ct->tar) {
- if (ct->tar->type != OB_CURVE) {
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- Curve *cu = ct->tar->data;
-
- /* auto-set 'Path' setting on curve so this works */
- cu->flag |= CU_PATH;
- }
- }
- }
- }
-
- /* free any temporary targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ test_constraint(owner, pchan, curcon, type);
}
}
}
@@ -524,6 +537,26 @@ void object_test_constraints(Object *owner)
}
}
+static void object_test_constraint(Object *owner, bConstraint *con)
+{
+ if (owner->type == OB_ARMATURE && owner->pose) {
+ if (BLI_findindex(&owner->constraints, con) != -1) {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+ else {
+ bPoseChannel *pchan;
+ for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ test_constraint(owner, pchan, con, CONSTRAINT_OBTYPE_BONE);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+}
/************************ generic functions for operators using constraint names and data context *********************/
@@ -1161,20 +1194,49 @@ void ED_object_constraint_update(Object *ob)
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
+static void object_pose_tag_update(Main *bmain, Object *ob)
+{
+ BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */
+ if (ob->proxy && ob->adt) {
+ /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
+ * after calling `BKE_pose_rebuild()`, which causes T43872.
+ * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones
+ * or not...
+ * XXX Temp hack until new depsgraph hopefully solves this. */
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+}
+
void ED_object_constraint_dependency_update(Main *bmain, Object *ob)
{
ED_object_constraint_update(ob);
if (ob->pose) {
- ob->pose->flag |= POSE_RECALC; /* Checks & sort pose channels. */
- if (ob->proxy && ob->adt) {
- /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
- * after calling `BKE_pose_rebuild()`, which causes T43872.
- * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones
- * or not...
- * XXX Temp hack until new depsgraph hopefully solves this. */
- ob->adt->recalc |= ADT_RECALC_ANIM;
- }
+ object_pose_tag_update(bmain, ob);
+ }
+ DAG_relations_tag_update(bmain);
+}
+
+void ED_object_constraint_tag_update(Object *ob, bConstraint *con)
+{
+ if (ob->pose) {
+ BKE_pose_tag_update_constraint_flags(ob->pose);
+ }
+
+ object_test_constraint(ob, con);
+
+ if (ob->type == OB_ARMATURE)
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ else
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+}
+
+void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con)
+{
+ ED_object_constraint_tag_update(ob, con);
+
+ if (ob->pose) {
+ object_pose_tag_update(bmain, ob);
}
DAG_relations_tag_update(bmain);
}
@@ -1198,7 +1260,10 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* there's no active constraint now, so make sure this is the case */
BKE_constraints_active_set(&ob->constraints, NULL);
ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
-
+
+ /* relatiols */
+ DAG_relations_tag_update(CTX_data_main(C));
+
/* notifiers */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
@@ -1422,8 +1487,8 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
BKE_constraints_copy(&chan->constraints, &pchan->constraints, true);
/* update flags (need to add here, not just copy) */
chan->constflag |= pchan->constflag;
-
- ob->pose->flag |= POSE_RECALC;
+
+ BKE_pose_tag_recalc(bmain, ob->pose);
DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
}
}
@@ -1600,7 +1665,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
Object *obt;
/* add new target object */
- obt = BKE_object_add(bmain, scene, OB_EMPTY);
+ obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
/* set layers OK */
newbase = BASACT;
@@ -1734,7 +1799,7 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
DAG_relations_tag_update(bmain);
if ((ob->type == OB_ARMATURE) && (pchan)) {
- ob->pose->flag |= POSE_RECALC; /* sort pose channels */
+ BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */
if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) {
/* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
* after calling `BKE_pose_rebuild()`, which causes T43872.
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index b39e8470a95..d6a1694b4b0 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -29,8 +29,6 @@
* \ingroup edobj
*/
-#include "MEM_guardedalloc.h"
-
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -59,7 +57,6 @@
#include "ED_object.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "object_intern.h"
@@ -325,7 +322,7 @@ static bool data_transfer_exec_is_object_valid(
static int data_transfer_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob_src = CTX_data_active_object(C);
+ Object *ob_src = ED_object_active_context(C);
ListBase ctx_objects;
CollectionPointerLink *ctx_ob_dst;
@@ -419,7 +416,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
/* Note this context poll is only really partial, it cannot check for all possible invalid cases. */
static int data_transfer_poll(bContext *C)
{
- Object *ob = ED_object_context(C);
+ Object *ob = ED_object_active_context(C);
ID *data = (ob) ? ob->data : NULL;
return (ob && ob->type == OB_MESH && data);
}
@@ -534,7 +531,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
/* Mapping options and filtering. */
RNA_def_boolean(ot->srna, "use_object_transform", true, "Object Transform",
- "Evaluate source and destination meshes in their respective object spaces");
+ "Evaluate source and destination meshes in global space");
RNA_def_boolean(ot->srna, "use_max_distance", false, "Only Neighbor Geometry",
"Source elements must be closer than given distance from destination one");
prop = RNA_def_float(ot->srna, "max_distance", 1.0f, 0.0f, FLT_MAX, "Max Distance",
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f7d51eb403f..3499a3cc364 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -65,6 +65,7 @@
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -318,7 +319,7 @@ void OBJECT_OT_hide_render_set(wmOperatorType *ot)
* Load EditMode data back into the object,
* optionally freeing the editmode data.
*/
-static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
+static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool freedata)
{
if (obedit == NULL) {
return false;
@@ -348,6 +349,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
ED_armature_from_edit(obedit->data);
if (freedata)
ED_armature_edit_free(obedit->data);
+ /* TODO(sergey): Pose channels might have been changed, so need
+ * to inform dependency graph about this. But is it really the
+ * best place to do this?
+ */
+ DAG_relations_tag_update(bmain);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
load_editNurb(obedit);
@@ -376,7 +382,8 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
bool ED_object_editmode_load(Object *obedit)
{
- return ED_object_editmode_load_ex(obedit, false);
+ /* TODO(sergey): use proper main here? */
+ return ED_object_editmode_load_ex(G.main, obedit, false);
}
void ED_object_editmode_exit(bContext *C, int flag)
@@ -389,7 +396,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
if (flag & EM_WAITCURSOR) waitcursor(1);
- if (ED_object_editmode_load_ex(obedit, freedata) == false) {
+ if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
if (UNLIKELY(scene->basact && (scene->basact->object->mode & OB_MODE_EDIT))) {
@@ -898,6 +905,8 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->rdamping = ob->rdamping;
base->object->min_vel = ob->min_vel;
base->object->max_vel = ob->max_vel;
+ base->object->min_angvel = ob->min_angvel;
+ base->object->max_angvel = ob->max_angvel;
if (ob->gameflag & OB_BOUNDS) {
base->object->collision_boundtype = ob->collision_boundtype;
}
@@ -1769,6 +1778,77 @@ void OBJECT_OT_game_property_remove(wmOperatorType *ot)
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
}
+#define GAME_PROPERTY_MOVE_UP 1
+#define GAME_PROPERTY_MOVE_DOWN -1
+
+static int game_property_move(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bProperty *prop;
+ bProperty *otherprop = NULL;
+ const int index = RNA_int_get(op->ptr, "index");
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ prop = BLI_findlink(&ob->prop, index);
+ /* invalid index */
+ if (prop == NULL)
+ return OPERATOR_CANCELLED;
+
+ if (dir == GAME_PROPERTY_MOVE_UP) {
+ otherprop = prop->prev;
+ }
+ else if (dir == GAME_PROPERTY_MOVE_DOWN) {
+ otherprop = prop->next;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (prop && otherprop) {
+ BLI_listbase_swaplinks(&ob->prop, prop, otherprop);
+
+ WM_event_add_notifier(C, NC_LOGIC, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_game_property_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_property_move[] = {
+ {GAME_PROPERTY_MOVE_UP, "UP", 0, "Up", ""},
+ {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Move Game Property";
+ ot->description = "Move game property";
+ ot->idname = "OBJECT_OT_game_property_move";
+
+ /* api callbacks */
+ ot->exec = game_property_move;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction",
+ "Direction for moving the property");
+}
+
+#undef GAME_PROPERTY_MOVE_UP
+#undef GAME_PROPERTY_MOVE_DOWN
+
#define COPY_PROPERTIES_REPLACE 1
#define COPY_PROPERTIES_MERGE 2
#define COPY_PROPERTIES_COPY 3
@@ -1966,6 +2046,8 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
ob_iter->rdamping = ob->rdamping;
ob_iter->min_vel = ob->min_vel;
ob_iter->max_vel = ob->max_vel;
+ ob_iter->min_angvel = ob->min_angvel;
+ ob_iter->max_angvel = ob->max_angvel;
ob_iter->obstacleRad = ob->obstacleRad;
ob_iter->mass = ob->mass;
copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 1d764ced524..8797b75a801 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -448,11 +448,12 @@ static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit)
Base *base, *basedit;
Object *ob;
- ob = BKE_object_add(bmain, scene, OB_EMPTY);
+ ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
basedit = BKE_scene_base_find(scene, obedit);
- base = BKE_scene_base_find(scene, ob);
+ base = scene->basact;
base->lay = ob->lay = obedit->lay;
+ BLI_assert(scene->basact->object == ob);
/* icky, BKE_object_add sets new base as active.
* so set it back to the original edit object */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 64fddf1b6a1..6344e04ef1b 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -32,17 +32,12 @@
#define __OBJECT_INTERN_H__
struct wmOperatorType;
-struct KeyBlock;
-struct Lattice;
-struct Curve;
struct Object;
-struct Mesh;
struct bContext;
struct StructRNA;
struct wmOperator;
struct ModifierData;
-struct HookModifierData;
/* add hook menu */
enum eObject_Hook_Add_Mode {
@@ -99,6 +94,7 @@ void OBJECT_OT_game_property_new(struct wmOperatorType *ot);
void OBJECT_OT_game_property_remove(struct wmOperatorType *ot);
void OBJECT_OT_game_property_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_property_clear(struct wmOperatorType *ot);
+void OBJECT_OT_game_property_move(struct wmOperatorType *ot);
void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot);
@@ -179,6 +175,7 @@ void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
+void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
@@ -233,7 +230,7 @@ void OBJECT_OT_vertex_group_levels(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_lock(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_fix(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot);
-void OBJECT_OT_vertex_group_blend(struct wmOperatorType *ot);
+void OBJECT_OT_vertex_group_smooth(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_quantize(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_limit_total(struct wmOperatorType *ot);
@@ -248,7 +245,7 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_warp.c */
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
@@ -274,7 +271,7 @@ void OBJECT_OT_lod_add(struct wmOperatorType *ot);
void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
/* object_random.c */
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index b577dab8a77..76d9facf701 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -713,7 +713,7 @@ static int lattice_flip_exec(bContext *C, wmOperator *op)
break;
default:
- printf("lattice_flip(): Unknown flipping axis (%d)\n", axis);
+ printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 710cf2dbdd2..ce9693793a4 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -96,7 +96,7 @@ static void modifier_skin_customdata_delete(struct Object *ob);
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
- ModifierTypeInfo *mti = modifierType_getInfo(type);
+ 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)) {
@@ -152,10 +152,10 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ob->pd = object_add_collision_fields(0);
ob->pd->deflect = 1;
- DAG_relations_tag_update(bmain);
}
- else if (type == eModifierType_Surface)
- DAG_relations_tag_update(bmain);
+ else if (type == eModifierType_Surface) {
+ /* pass */
+ }
else if (type == eModifierType_Multires) {
/* set totlvl from existing MDISPS layer if object already had it */
multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob);
@@ -172,6 +172,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(bmain);
return new_md;
}
@@ -247,7 +248,7 @@ static bool object_has_modifier_cb(Object *ob, void *data)
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
ModifierData *md;
- int totlevel = *((int *)totlevel_v);
+ int totlevel = *((char *)totlevel_v);
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Multires) {
@@ -319,6 +320,8 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
+ DAG_relations_tag_update(bmain);
+
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -368,10 +371,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->prev) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->type != eModifierTypeType_OnlyDeform) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
@@ -389,10 +392,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md
int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
if (nmti->type != eModifierTypeType_OnlyDeform) {
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
@@ -459,7 +462,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
if (totvert == 0) return 0;
/* add new mesh */
- obn = BKE_object_add(bmain, scene, OB_MESH);
+ obn = BKE_object_add(bmain, scene, OB_MESH, NULL);
me = obn->data;
me->totvert = totvert;
@@ -518,7 +521,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -578,7 +581,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -742,7 +745,7 @@ static EnumPropertyItem *modifier_add_itemf(bContext *C, PointerRNA *UNUSED(ptr)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL, *md_item, *group_item = NULL;
- ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
int totitem = 0, a;
if (!ob)
@@ -1704,7 +1707,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
NULL,
me->totvert);
- arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE);
+ arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL);
BKE_object_transform_copy(arm_ob, skin_ob);
arm = arm_ob->data;
arm->layer = 1;
@@ -1815,6 +1818,73 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+/************************ delta mush bind operator *********************/
+
+static int correctivesmooth_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0);
+}
+
+static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth);
+ bool is_bind;
+
+ if (!csmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ is_bind = (csmd->bind_coords != NULL);
+
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ if (is_bind) {
+ /* toggle off */
+ csmd->bind_coords_num = 0;
+ }
+ else {
+ /* signal to modifier to recalculate */
+ csmd->bind_coords_num = (unsigned int)-1;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return correctivesmooth_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Corrective Smooth Bind";
+ ot->description = "Bind base pose in Corrective Smooth modifier";
+ ot->idname = "OBJECT_OT_correctivesmooth_bind";
+
+ /* api callbacks */
+ ot->poll = correctivesmooth_poll;
+ ot->invoke = correctivesmooth_bind_invoke;
+ ot->exec = correctivesmooth_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
/************************ mdef bind operator *********************/
@@ -1978,7 +2048,7 @@ static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData
do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
- BKE_init_ocean(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
+ BKE_ocean_init(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
omd->depth, omd->time,
do_heightfield, do_chop, do_normals, do_jacobian,
@@ -2036,7 +2106,7 @@ static void oceanbake_startjob(void *customdata, short *stop, short *do_update,
G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
- BKE_bake_ocean(oj->ocean, oj->och, oceanbake_update, (void *)oj);
+ BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj);
*do_update = true;
*stop = 0;
@@ -2047,7 +2117,7 @@ static void oceanbake_endjob(void *customdata)
OceanBakeJob *oj = customdata;
if (oj->ocean) {
- BKE_free_ocean(oj->ocean);
+ BKE_ocean_free(oj->ocean);
oj->ocean = NULL;
}
@@ -2078,7 +2148,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob),
+ och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(ob),
omd->bakestart, omd->bakeend, omd->wave_scale,
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
@@ -2112,11 +2182,11 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
/* make a copy of ocean to use for baking - threadsafety */
- ocean = BKE_add_ocean();
+ ocean = BKE_ocean_add();
init_ocean_modifier_bake(ocean, omd);
#if 0
- BKE_bake_ocean(ocean, och);
+ BKE_ocean_bake(ocean, och);
omd->oceancache = och;
omd->cached = true;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 15eb9090ce5..22cac8638d9 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -144,6 +144,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
WM_operatortype_append(OBJECT_OT_ocean_bake);
@@ -185,7 +186,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_fix);
WM_operatortype_append(OBJECT_OT_vertex_group_invert);
WM_operatortype_append(OBJECT_OT_vertex_group_levels);
- WM_operatortype_append(OBJECT_OT_vertex_group_blend);
+ WM_operatortype_append(OBJECT_OT_vertex_group_smooth);
WM_operatortype_append(OBJECT_OT_vertex_group_clean);
WM_operatortype_append(OBJECT_OT_vertex_group_quantize);
WM_operatortype_append(OBJECT_OT_vertex_group_limit_total);
@@ -199,12 +200,13 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active_vertex);
WM_operatortype_append(OBJECT_OT_vertex_weight_copy);
- WM_operatortype_append(OBJECT_OT_vertex_warp);
+ WM_operatortype_append(TRANSFORM_OT_vertex_warp);
WM_operatortype_append(OBJECT_OT_game_property_new);
WM_operatortype_append(OBJECT_OT_game_property_remove);
WM_operatortype_append(OBJECT_OT_game_property_copy);
WM_operatortype_append(OBJECT_OT_game_property_clear);
+ WM_operatortype_append(OBJECT_OT_game_property_move);
WM_operatortype_append(OBJECT_OT_logic_bricks_copy);
WM_operatortype_append(OBJECT_OT_game_physics_copy);
@@ -247,7 +249,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_lod_add);
WM_operatortype_append(OBJECT_OT_lod_remove);
- WM_operatortype_append(OBJECT_OT_vertex_random);
+ WM_operatortype_append(TRANSFORM_OT_vertex_random);
WM_operatortype_append(OBJECT_OT_data_transfer);
WM_operatortype_append(OBJECT_OT_datalayout_transfer);
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 41b26b98047..a293f7a950e 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -124,12 +124,12 @@ static int object_rand_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Randomize";
ot->description = "Randomize vertices";
- ot->idname = "OBJECT_OT_vertex_random";
+ ot->idname = "TRANSFORM_OT_vertex_random";
/* api callbacks */
ot->exec = object_rand_verts_exec;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index bfa501c3732..c2d2bffbbe5 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -342,12 +342,10 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
Base *newbase, *oldbase = BASACT;
char name[MAX_ID_NAME + 4];
- /* Add new object for the proxy */
- newob = BKE_object_add(bmain, scene, OB_EMPTY);
-
BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2);
- rename_id(&newob->id, name);
+ /* Add new object for the proxy */
+ newob = BKE_object_add(bmain, scene, OB_EMPTY, name);
/* set layers OK */
newbase = BASACT; /* BKE_object_add sets active... */
@@ -573,6 +571,9 @@ void ED_object_parent(Object *ob, Object *par, const int type, const char *subst
return;
}
+ /* Other partypes are deprecated, do not use here! */
+ BLI_assert(ELEM(type & PARTYPE, PAROBJECT, PARSKEL, PARVERT1, PARVERT3, PARBONE));
+
/* this could use some more checks */
ob->parent = par;
@@ -1574,13 +1575,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob_dst->id, 0);
break;
case MAKE_LINKS_ANIMDATA:
- BKE_copy_animdata_id((ID *)ob_dst, (ID *)ob_src, false);
+ BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
if (obdata_id->lib) {
is_lib = true;
break;
}
- BKE_copy_animdata_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
+ BKE_animdata_copy_id((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;
@@ -1871,7 +1872,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
case OB_MESH:
ob->data = me = BKE_mesh_copy(ob->data);
if (me->key)
- BKE_copy_animdata_id_action((ID *)me->key);
+ BKE_animdata_copy_id_action((ID *)me->key);
break;
case OB_MBALL:
ob->data = BKE_mball_copy(ob->data);
@@ -1883,12 +1884,12 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
- BKE_copy_animdata_id_action((ID *)cu->key);
+ BKE_animdata_copy_id_action((ID *)cu->key);
break;
case OB_LATTICE:
ob->data = lat = BKE_lattice_copy(ob->data);
if (lat->key)
- BKE_copy_animdata_id_action((ID *)lat->key);
+ BKE_animdata_copy_id_action((ID *)lat->key);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -1909,7 +1910,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_copy_animdata_id_action((ID *)ob->data);
+ BKE_animdata_copy_id_action((ID *)ob->data);
id->us--;
id->newid = ob->data;
@@ -1933,7 +1934,7 @@ static void single_object_action_users(Scene *scene, const int flag)
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BKE_copy_animdata_id_action(&ob->id);
+ BKE_animdata_copy_id_action(&ob->id);
}
}
}
@@ -1956,7 +1957,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (ma->id.us > 1) {
man = BKE_material_copy(ma);
- BKE_copy_animdata_id_action(&man->id);
+ BKE_animdata_copy_id_action(&man->id);
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1967,7 +1968,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (tex->id.us > 1) {
tex->id.us--;
tex = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&tex->id);
+ BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
}
}
@@ -1994,7 +1995,7 @@ static void do_single_tex_user(Tex **from)
}
else if (tex->id.us > 1) {
texn = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&texn->id);
+ BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
tex->id.us--;
*from = texn;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index fb9687da6df..ed71af71ac9 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -48,7 +48,6 @@
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "BKE_context.h"
@@ -78,7 +77,7 @@
static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix)
{
KeyBlock *kb;
- if ((kb = BKE_object_insert_shape_key(ob, NULL, from_mix))) {
+ if ((kb = BKE_object_shapekey_insert(ob, NULL, from_mix))) {
Key *key = BKE_key_from_object(ob);
/* for absolute shape keys, new keys may not be added last */
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
@@ -89,89 +88,21 @@ static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix
/*********************** remove shape key ***********************/
-static bool ED_object_shape_key_remove_all(Main *bmain, Object *ob)
+static bool object_shapekey_remove(Main *bmain, Object *ob)
{
- Key *key;
+ KeyBlock *kb;
+ Key *key = BKE_key_from_object(ob);
- key = BKE_key_from_object(ob);
- if (key == NULL)
+ if (key == NULL) {
return false;
-
- switch (GS(key->from->name)) {
- case ID_ME: ((Mesh *)key->from)->key = NULL; break;
- case ID_CU: ((Curve *)key->from)->key = NULL; break;
- case ID_LT: ((Lattice *)key->from)->key = NULL; break;
}
- BKE_libblock_free_us(bmain, key);
-
- return true;
-}
-
-static bool ED_object_shape_key_remove(Main *bmain, Object *ob)
-{
- KeyBlock *kb, *rkb;
- Key *key;
-
- key = BKE_key_from_object(ob);
- if (key == NULL)
- return false;
-
kb = BLI_findlink(&key->block, ob->shapenr - 1);
-
if (kb) {
- for (rkb = key->block.first; rkb; rkb = rkb->next) {
- if (rkb->relative == ob->shapenr - 1) {
- /* remap to the 'Basis' */
- rkb->relative = 0;
- }
- else if (rkb->relative >= ob->shapenr) {
- /* Fix positional shift of the keys when kb is deleted from the list */
- rkb->relative -= 1;
- }
- }
-
- BLI_remlink(&key->block, kb);
- key->totkey--;
- if (key->refkey == kb) {
- key->refkey = key->block.first;
-
- if (key->refkey) {
- /* apply new basis key on original data */
- switch (ob->type) {
- case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
- break;
- case OB_CURVE:
- case OB_SURF:
- BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
- break;
- case OB_LATTICE:
- BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
- break;
- }
- }
- }
-
- if (kb->data) MEM_freeN(kb->data);
- MEM_freeN(kb);
-
- if (ob->shapenr > 1) {
- ob->shapenr--;
- }
+ return BKE_object_shapekey_remove(bmain, ob, kb);
}
-
- if (key->totkey == 0) {
- switch (GS(key->from->name)) {
- case ID_ME: ((Mesh *)key->from)->key = NULL; break;
- case ID_CU: ((Curve *)key->from)->key = NULL; break;
- case ID_LT: ((Lattice *)key->from)->key = NULL; break;
- }
- BKE_libblock_free_us(bmain, key);
- }
-
- return true;
+ return false;
}
static bool object_shape_key_mirror(bContext *C, Object *ob,
@@ -332,6 +263,9 @@ static int shape_key_add_exec(bContext *C, wmOperator *op)
ED_object_shape_key_add(C, ob, from_mix);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(CTX_data_main(C));
+
return OPERATOR_FINISHED;
}
@@ -360,14 +294,15 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
bool changed = false;
if (RNA_boolean_get(op->ptr, "all")) {
- changed = ED_object_shape_key_remove_all(bmain, ob);
+ changed = BKE_object_shapekey_free(bmain, ob);
}
else {
- changed = ED_object_shape_key_remove(bmain, ob);
+ changed = object_shapekey_remove(bmain, ob);
}
if (changed) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 92fe5ded4dd..340b662c0ef 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -939,8 +939,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* convert the offset to parent space */
BKE_object_to_mat4(ob, obmat);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(obmat, centn); /* omit translation part */
+ mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, centn);
@@ -970,8 +969,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
ob_other->flag |= OB_DONE;
DAG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(ob_other->obmat, centn); /* omit translation part */
+ mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
add_v3_v3(ob_other->loc, centn);
BKE_object_where_is_calc(scene, ob_other);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index f885cbbb24f..f2b2923ee0d 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -50,6 +50,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
+#include "BLI_stackdefines.h"
#include "BKE_context.h"
@@ -427,6 +428,48 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
return true;
}
+void ED_vgroup_parray_to_weight_array(
+ const MDeformVert **dvert_array, const int dvert_tot,
+ float *dvert_weights, const int def_nr)
+{
+ int i;
+
+ for (i = 0; i < dvert_tot; i++) {
+ const MDeformVert *dv = dvert_array[i];
+ dvert_weights[i] = dv ? defvert_find_weight(dv, def_nr) : 0.0f;
+ }
+}
+
+void ED_vgroup_parray_from_weight_array(
+ MDeformVert **dvert_array, const int dvert_tot,
+ const float *dvert_weights, const int def_nr, const bool remove_zero)
+{
+ int i;
+
+ for (i = 0; i < dvert_tot; i++) {
+ MDeformVert *dv = dvert_array[i];
+ if (dv) {
+ if (dvert_weights[i] > 0.0f) {
+ MDeformWeight *dw = defvert_verify_index(dv, def_nr);
+ BLI_assert(IN_RANGE_INCL(dvert_weights[i], 0.0f, 1.0f));
+ dw->weight = dvert_weights[i];
+ }
+ else {
+ MDeformWeight *dw = defvert_find_index(dv, def_nr);
+ if (dw) {
+ if (remove_zero) {
+ defvert_remove_group(dv, dw);
+ }
+ else {
+ dw->weight = 0.0f;
+ }
+ }
+ }
+ }
+ }
+}
+
+
/* TODO, cache flip data to speedup calls within a loop. */
static void mesh_defvert_mirror_update_internal(Object *ob,
MDeformVert *dvert_dst, MDeformVert *dvert_src,
@@ -1177,7 +1220,7 @@ static void getVerticalAndHorizontalChange(const float norm[3], float d, const f
dists[index] = dot_v3v3(norm, end) + d;
/* vertical change */
changes[index][0] = dists[index] - distToStart;
- //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]);
+ //printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]);
/* horizontal change */
changes[index][1] = len_v3v3(projA, projB);
}
@@ -1631,9 +1674,17 @@ static void vgroup_invert_subset(Object *ob,
}
}
-static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot,
- const int subset_count,
- const float fac)
+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 ifac = 1.0f - fac;
MDeformVert **dvert_array = NULL;
@@ -1642,6 +1693,10 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
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 int expand_sign = signum_i(fac_expand);
+ const float expand = fabsf(fac_expand);
+ const float iexpand = 1.0f - expand;
+
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em ? em->bm : NULL;
Mesh *me = em ? NULL : ob->data;
@@ -1649,7 +1704,15 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
MeshElemMap *emap;
int *emap_mem;
- BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *);
+ float *weight_accum_prev;
+ float *weight_accum_curr;
+
+ unsigned int subset_index;
+
+ /* vertex indices that will be smoothed, (only to avoid iterating over verts that do nothing) */
+ unsigned int *verts_used;
+ STACK_DECLARE(verts_used);
+
BKE_object_defgroup_subset_to_index_array(vgroup_validmap, vgroup_tot, vgroup_subset_map);
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false);
@@ -1657,87 +1720,159 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
if (bm) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
emap = NULL;
emap_mem = NULL;
}
else {
- BKE_mesh_vert_edge_map_create(&emap, &emap_mem,
- me->medge, me->totvert, me->totedge);
+ BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
}
+ weight_accum_prev = MEM_mallocN(sizeof(*weight_accum_prev) * dvert_tot, __func__);
+ weight_accum_curr = MEM_mallocN(sizeof(*weight_accum_curr) * dvert_tot, __func__);
+
+ verts_used = MEM_mallocN(sizeof(*verts_used) * dvert_tot, __func__);
+ STACK_INIT(verts_used, dvert_tot);
- for (i = 0; i < dvert_tot; i++) {
- MDeformVert *dv;
- int dv_stack_tot = 0;
- int j;
- /* in case its not selected */
- if (bm) {
+ /* initialize used verts */
+ if (bm) {
+ for (i = 0; i < dvert_tot; i++) {
BMVert *v = BM_vert_at_index(bm, i);
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
BMVert *v_other = BM_edge_other_vert(e, v);
- const int i_other = BM_elem_index_get(v_other);
-
- if (BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) {
- dv = dvert_array[i_other];
- BLI_SMALLSTACK_PUSH(dv_stack, dv);
- dv_stack_tot++;
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == (BM_elem_flag_test(v_other, BM_ELEM_SELECT) != 0)))
+ {
+ STACK_PUSH(verts_used, i);
+ break;
}
}
}
}
- else {
+ }
+ else {
+ for (i = 0; i < dvert_tot; i++) {
MVert *v = &me->mvert[i];
if (v->flag & SELECT) {
+ int j;
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 ((v_other->flag & SELECT) == 0) {
- dv = dvert_array[i_other];
- BLI_SMALLSTACK_PUSH(dv_stack, dv);
- dv_stack_tot++;
+ if ((source == WEIGHT_SMOOTH_ALL) ||
+ (source == ((v_other->flag & SELECT) != 0)))
+ {
+ STACK_PUSH(verts_used, i);
+ break;
}
}
}
}
+ }
- if (dv_stack_tot) {
- const float dv_mul = 1.0f / (float)dv_stack_tot;
-
- /* vgroup_subset_weights is zero'd at this point */
- while ((dv = BLI_SMALLSTACK_POP(dv_stack))) {
- for (j = 0; j < subset_count; j++) {
- vgroup_subset_weights[j] += dv_mul * defvert_find_weight(dv, vgroup_subset_map[j]);
- }
- }
-
- dv = dvert_array[i];
- for (j = 0; j < subset_count; j++) {
- MDeformWeight *dw;
- if (vgroup_subset_weights[j] > 0.0f) {
- dw = defvert_verify_index(dv, vgroup_subset_map[j]);
+ for (subset_index = 0; subset_index < subset_count; subset_index++) {
+ const int def_nr = vgroup_subset_map[subset_index];
+ int iter;
+
+ ED_vgroup_parray_to_weight_array((const MDeformVert **)dvert_array, dvert_tot, weight_accum_prev, def_nr);
+ memcpy(weight_accum_curr, weight_accum_prev, sizeof(*weight_accum_curr) * dvert_tot);
+
+ for (iter = 0; iter < repeat; iter++) {
+ unsigned *vi_step, *vi_end = verts_used + STACK_SIZE(verts_used);
+
+ /* avoid looping over all verts */
+ // for (i = 0; i < dvert_tot; i++)
+ for (vi_step = verts_used; vi_step != vi_end; vi_step++) {
+ const unsigned int i = *vi_step;
+ float weight_tot = 0.0f;
+ float weight = 0.0f;
+
+#define WEIGHT_ACCUMULATE \
+ { \
+ float weight_other = weight_accum_prev[i_other]; \
+ float tot_factor = 1.0f; \
+ if (expand_sign == 1) { /* expand */ \
+ if (weight_other < weight_accum_prev[i]) { \
+ weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ tot_factor = iexpand; \
+ } \
+ } \
+ else if (expand_sign == -1) { /* contract */ \
+ if (weight_other > weight_accum_prev[i]) { \
+ weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ tot_factor = iexpand; \
+ } \
+ } \
+ weight += tot_factor * weight_other; \
+ weight_tot += tot_factor; \
+ } ((void)0)
+
+
+ if (bm) {
+ BMVert *v = BM_vert_at_index(bm, i);
+ BMIter eiter;
+ BMEdge *e;
+
+ /* checked already */
+ BLI_assert(BM_elem_flag_test(v, BM_ELEM_SELECT));
+
+ 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)))
+ {
+ const int i_other = BM_elem_index_get(v_other);
+
+ WEIGHT_ACCUMULATE;
+ }
+ }
}
else {
- dw = defvert_find_index(dv, vgroup_subset_map[j]);
- }
+ int j;
- if (dw) {
- dw->weight = (fac * vgroup_subset_weights[j]) + (ifac * dw->weight);
- CLAMP(dw->weight, 0.0f, 1.0f);
+ /* checked already */
+ BLI_assert(me->mvert[i].flag & SELECT);
+
+ 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)))
+ {
+ WEIGHT_ACCUMULATE;
+ }
+ }
}
- /* zero for next iteration */
- vgroup_subset_weights[j] = 0.0f;
+#undef WEIGHT_ACCUMULATE
+
+ if (weight_tot != 0.0f) {
+ weight /= weight_tot;
+ weight = (weight_accum_prev[i] * ifac) + (weight * fac);
+
+ /* should be within range, just clamp because of float precision */
+ CLAMP(weight, 0.0f, 1.0f);
+ weight_accum_curr[i] = weight;
+ }
}
+
+ SWAP(float *, weight_accum_curr, weight_accum_prev);
}
+
+ ED_vgroup_parray_from_weight_array(dvert_array, dvert_tot, weight_accum_prev, def_nr, true);
}
+ MEM_freeN(weight_accum_curr);
+ MEM_freeN(weight_accum_prev);
+ MEM_freeN(verts_used);
+
if (bm) {
/* pass */
}
@@ -2062,7 +2197,7 @@ void ED_vgroup_mirror(Object *ob,
/* object mode / weight paint */
MVert *mv, *mv_mirr;
int vidx, vidx_mirr;
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->dvert == NULL) {
goto cleanup;
@@ -2315,16 +2450,43 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
}
/* editmode _or_ weight paint vertex sel */
-static int vertex_group_vert_select_poll(bContext *C)
+static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_flag)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
if (!(ob && !ob->id.lib && data && !data->lib))
- return 0;
+ return false;
- return (BKE_object_is_in_editmode_vgroup(ob) ||
- BKE_object_is_in_wpaint_select_vert(ob));
+ if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) {
+ return false;
+ }
+
+ if (BKE_object_is_in_editmode_vgroup(ob)) {
+ return true;
+ }
+ else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ 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 {
+ return false;
+ }
+}
+
+static int vertex_group_vert_select_poll(bContext *C)
+{
+ return vertex_group_vert_select_poll_ex(C, 0);
+}
+
+static int vertex_group_mesh_vert_select_poll(bContext *C)
+{
+ return vertex_group_vert_select_poll_ex(C, (1 << OB_MESH));
}
/* editmode _or_ weight paint vertex sel and active group unlocked */
@@ -2851,17 +3013,19 @@ void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
"Remove verts from groups that have zero weight after inverting");
}
-
-static int vertex_group_blend_exec(bContext *C, wmOperator *op)
+static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- float fac = RNA_float_get(op->ptr, "factor");
+ 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_blend_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac);
+ vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand, source);
MEM_freeN((void *)vgroup_validmap);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -2871,60 +3035,34 @@ static int vertex_group_blend_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* check we have a vertex selection, either in weight paint or editmode */
-static int vertex_group_blend_poll(bContext *C)
+void OBJECT_OT_vertex_group_smooth(wmOperatorType *ot)
{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
-
- if (!(ob && !ob->id.lib && data && !data->lib))
- return false;
-
- if (ob->type != OB_MESH) {
- return false;
- }
-
- if (BKE_object_is_in_editmode_vgroup(ob)) {
- return true;
- }
- else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- if (ME_EDIT_PAINT_SEL_MODE(((Mesh *)data)) == SCE_SELECT_VERTEX) {
- return true;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Vertex select needs to be enabled in weight paint mode");
- return false;
- }
-
- }
- else {
- return false;
- }
-}
-
-void OBJECT_OT_vertex_group_blend(wmOperatorType *ot)
-{
- PropertyRNA *prop;
+ 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 = "Blend Vertex Group";
- ot->idname = "OBJECT_OT_vertex_group_blend";
- ot->description = "Blend selected vertex weights with unselected for the active group";
+ 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_blend_poll;
- ot->exec = vertex_group_blend_exec;
+ ot->poll = vertex_group_mesh_vert_select_poll;
+ ot->exec = vertex_group_smooth_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
vgroup_operator_subset_select_props(ot, true);
- prop = RNA_def_property(ot->srna, "factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_ui_text(prop, "Factor", "");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_default(prop, 1.0f);
-}
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
+ 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 7413bb07c4c..9f4da87903d 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -275,14 +275,14 @@ static int object_warp_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Warp";
ot->description = "Warp vertices around the cursor";
- ot->idname = "OBJECT_OT_vertex_warp";
+ ot->idname = "TRANSFORM_OT_vertex_warp";
/* api callbacks */
ot->exec = object_warp_verts_exec;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 6c90e319bc6..f25679986a5 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -400,12 +400,12 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
/* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */
view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
- if ((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- view3d_validate_backbuf(&data->vc);
+ ED_view3d_backbuf_validate(&data->vc);
/* we may need to force an update here by setting the rv3d as dirty
* for now it seems ok, but take care!:
* rv3d->depths->dirty = 1; */
@@ -414,18 +414,18 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
}
}
-static void PE_create_shape_tree(PEData *data, Object *shapeob)
+static bool PE_create_shape_tree(PEData *data, Object *shapeob)
{
DerivedMesh *dm = shapeob->derivedFinal;
memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
if (!dm) {
- return;
+ return false;
}
DM_ensure_tessface(dm);
- bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8);
+ return bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8);
}
static void PE_free_shape_tree(PEData *data)
@@ -443,8 +443,8 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
float depth;
/* nothing to do */
- if ((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
- return 1;
+ if (!V3D_IS_ZBUF(v3d))
+ return true;
/* used to calculate here but all callers have the screen_co already, so pass as arg */
#if 0
@@ -4059,11 +4059,12 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot)
static int shape_cut_poll(bContext *C)
{
if (PE_hair_poll(C)) {
- Scene *scene= CTX_data_scene(C);
- ParticleEditSettings *pset= PE_settings(scene);
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
- if (pset->shape_object)
+ if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
return true;
+ }
}
return false;
@@ -4179,7 +4180,10 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
int removed;
PE_set_data(C, &data);
- PE_create_shape_tree(&data, shapeob);
+ if (!PE_create_shape_tree(&data, shapeob)) {
+ /* shapeob may not have faces... */
+ return OPERATOR_CANCELLED;
+ }
if (selected)
foreach_selected_point(&data, shape_cut);
@@ -4445,7 +4449,7 @@ void PE_undo_step(Scene *scene, int step)
DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
}
-int PE_undo_valid(Scene *scene)
+bool PE_undo_is_valid(Scene *scene)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
@@ -4496,18 +4500,19 @@ void PE_undo_number(Scene *scene, int nr)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, int nr, int *active)
+const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
PTCacheUndo *undo;
- if (active) *active= 0;
+ if (r_active) *r_active = false;
if (edit) {
undo= BLI_findlink(&edit->undo, nr);
if (undo) {
- if (active && undo==edit->curundo)
- *active= 1;
+ if (r_active && (undo == edit->curundo)) {
+ *r_active = true;
+ }
return undo->name;
}
}
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 9b4f128ef86..c8b944f7d2a 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -348,6 +348,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
if (changed) {
/* send updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* done */
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index f9377d576bf..54429f9f066 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -32,9 +32,9 @@
#ifndef __RENDER_INTERN_H__
#define __RENDER_INTERN_H__
+struct bContext;
+struct RenderEngine;
struct wmOperatorType;
-struct RenderResult;
-struct Scene;
struct ScrArea;
/* render_shading.c */
@@ -44,6 +44,7 @@ void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_select(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot);
+void OBJECT_OT_material_slot_move(struct wmOperatorType *ot);
void MATERIAL_OT_new(struct wmOperatorType *ot);
void TEXTURE_OT_new(struct wmOperatorType *ot);
@@ -55,6 +56,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_render_view_add(struct wmOperatorType *ot);
+void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
+
#ifdef WITH_FREESTYLE
void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot);
void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 1c9f32697d4..2ba1e615a9e 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -48,6 +48,7 @@
#include "DNA_userdef_types.h"
#include "BKE_blender.h"
+#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
@@ -116,7 +117,7 @@ typedef struct RenderJob {
} RenderJob;
/* called inside thread! */
-static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect)
+static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname)
{
Scene *scene = rj->scene;
const float *rectf = NULL;
@@ -187,12 +188,16 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
* - sergey -
*/
/* TODO(sergey): Need to check has_combined here? */
- if (iuser->pass == 0) {
+ if (iuser->passtype == SCE_PASS_COMBINED) {
+ RenderView *rv;
+ size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
+ rv = RE_RenderViewGetById(rr, view_id);
+
/* find current float rect for display, first case is after composite... still weak */
- if (rr->rectf)
- rectf = rr->rectf;
+ if (rv->rectf)
+ rectf = rv->rectf;
else {
- if (rr->rect32) {
+ if (rv->rect32) {
/* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey)
@@ -201,8 +206,8 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
return;
}
else {
- if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
- rectf = rr->renlay->rectf;
+ if (rr->renlay == NULL) return;
+ rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@@ -518,7 +523,6 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- iuser->pass = sima->iuser.pass;
iuser->layer = sima->iuser.layer;
RE_ReleaseResult(rj->re);
@@ -531,6 +535,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
+ const char *viewname = RE_GetActiveRenderView(rj->re);
/* only update if we are displaying the slot being rendered */
if (ima->render_slot != ima->last_render_slot) {
@@ -563,7 +568,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
- image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect);
+ image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname);
}
/* make jobs timer to send notifier */
@@ -891,6 +896,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->write_still = is_write_still && !is_animation;
rj->iuser.scene = scene;
rj->iuser.ok = 1;
+ rj->iuser.passtype = SCE_PASS_COMBINED;
rj->reports = op->reports;
rj->orig_layer = 0;
rj->last_layer = 0;
@@ -1227,10 +1233,10 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
RenderData rdata;
- /* no osa, blur, seq, layers, etc for preview render */
+ /* no osa, blur, seq, layers, savebuffer etc for preview render */
rdata = rp->scene->r;
rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
- rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE);
+ rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE);
rdata.scemode |= R_VIEWPORT_PREVIEW;
/* we do use layers, but only active */
@@ -1487,7 +1493,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
if (re == NULL) return;
}
- RE_AcquireResultImage(re, &rres);
+ /* Viewport render preview doesn't support multiview, view hardcoded to 0 */
+ RE_AcquireResultImage(re, &rres, 0);
if (rres.rectf) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 402e72db217..5c69748e423 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
+#include "BLI_threads.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -103,11 +104,17 @@ typedef struct OGLRender {
bMovieHandle *mh;
int cfrao, nfra;
+ size_t totvideos;
+
+ /* quick lookup */
+ int view_id;
+
/* wm vars for timer and progress cursor */
wmWindowManager *wm;
wmWindow *win;
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
+ void **movie_ctx_arr;
} OGLRender;
/* added because v3d is not always valid */
@@ -121,25 +128,144 @@ static unsigned int screen_opengl_layers(OGLRender *oglrender)
}
}
-static void screen_opengl_render_apply(OGLRender *oglrender)
+static bool screen_opengl_is_multiview(OGLRender *oglrender)
+{
+ View3D *v3d = oglrender->v3d;
+ RegionView3D *rv3d = oglrender->rv3d;
+ RenderData *rd = &oglrender->scene->r;
+
+ if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL))))
+ return false;
+
+ return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+}
+
+static void screen_opengl_views_setup(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ SceneRenderView *srv;
+ bool is_multiview;
+ Object *camera;
+ View3D *v3d = oglrender->v3d;
+
+ RenderData *rd = &oglrender->scene->r;
+
+ rr = RE_AcquireResultWrite(oglrender->re);
+
+ is_multiview = screen_opengl_is_multiview(oglrender);
+
+ if (!is_multiview) {
+ /* we only have one view when multiview is off */
+ rv = rr->views.first;
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_addtail(&rr->views, rv);
+ }
+
+ while (rv->next) {
+ RenderView *rv_del = rv->next;
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+ else {
+ if (!oglrender->is_sequencer)
+ RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
+
+ /* remove all the views that are not needed */
+ rv = rr->views.last;
+ while (rv) {
+ srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (rv->rectf == NULL)
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ rv = rv->prev;
+ }
+ else {
+ RenderView *rv_del = rv;
+ rv = rv_del->prev;
+
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+
+ /* create all the views that are needed */
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+
+ rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
+ BLI_addtail(&rr->views, rv);
+ }
+ }
+ }
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ if (rv->rectf == NULL) {
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ }
+ }
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+ if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
+ oglrender->ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ oglrender->ima->flag &= ~IMA_IS_STEREO;
+ oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
+ }
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+
+ /* will only work for non multiview correctly */
+ if (v3d) {
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
+ BKE_render_result_stamp_info(oglrender->scene, camera, rr);
+ }
+ else {
+ BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr);
+ }
+
+ RE_ReleaseResult(oglrender->re);
+}
+
+static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
Scene *scene = oglrender->scene;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- RenderResult *rr;
Object *camera = NULL;
ImBuf *ibuf;
- void *lock;
float winmat[4][4];
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
const short view_context = (v3d != NULL);
bool draw_bgpic = true;
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
-
- rr = RE_AcquireResultRead(oglrender->re);
+ const char *viewname = RE_GetActiveRenderView(oglrender->re);
if (oglrender->is_sequencer) {
SeqRenderData context;
@@ -152,6 +278,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
oglrender->sizex, oglrender->sizey, 100.0f,
&context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
if (ibuf) {
@@ -175,7 +302,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
}
- memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
+ memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
IMB_freeImBuf(linear_ibuf);
}
@@ -199,10 +326,12 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
+ BLI_assert(rectf != NULL);
+
for (i = 0; i < sizex * sizey * 4; i += 4) {
float col_src[4];
rgba_uchar_to_float(col_src, &gp_rect[i]);
- blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src);
+ blend_color_mix_float(&rectf[i], &rectf[i], col_src);
}
GPU_offscreen_unbind(oglrender->ofs, true);
@@ -220,10 +349,17 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
- /*int is_ortho = scene->r.mode & R_ORTHO;*/
- camera = v3d->camera;
+#if 0
+ const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
+#endif
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
- is_persp = true;
+ if (camera->type == OB_CAMERA) {
+ Camera *cam = camera->data;
+ is_persp = cam->type == CAM_PERSP;
+ }
+ else
+ is_persp = true;
BKE_camera_to_gpu_dof(camera, &fx_settings);
}
else {
@@ -243,7 +379,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
}
else {
@@ -259,7 +395,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -275,7 +411,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -295,7 +431,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
char err_out[256] = "unknown";
ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
IB_rect, OB_SOLID, false, true, true,
- (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out);
+ (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
camera = scene->camera;
if (ibuf_view) {
@@ -320,7 +456,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
if (rect) {
int profile_to;
-
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
+
if (BKE_scene_check_color_management_enabled(scene))
profile_to = IB_PROFILE_LINEAR_RGB;
else
@@ -328,47 +465,68 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* sequencer has got trickier conversion happened above
* also assume opengl's space matches byte buffer color space */
- IMB_buffer_float_from_byte(rr->rectf, rect,
+ IMB_buffer_float_from_byte(rectf, rect,
profile_to, IB_PROFILE_SRGB, true,
oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
+
+ /* rr->rectf is now filled with image data */
+
+ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
+ BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
+
+ MEM_freeN(rect);
}
+}
- /* rr->rectf is now filled with image data */
+static void screen_opengl_render_write(OGLRender *oglrender)
+{
+ Scene *scene = oglrender->scene;
+ RenderResult *rr;
+ bool ok;
+ char name[FILE_MAX];
+
+ rr = RE_AcquireResultRead(oglrender->re);
+
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
+
+ /* write images as individual images or stereo */
+ BKE_render_result_stamp_info(scene, scene->camera, rr);
+ ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
+
+ RE_ReleaseResultImage(oglrender->re);
+
+ if (ok) printf("OpenGL Render written to '%s'\n", name);
+ else printf("OpenGL Render failed to write '%s'\n", name);
+}
+
+static void screen_opengl_render_apply(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ int view_id;
+ ImBuf *ibuf;
+ void *lock;
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
+ rr = RE_AcquireResultRead(oglrender->re);
+ for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ RE_SetActiveRenderView(oglrender->re, rv->name);
+ oglrender->view_id = view_id;
+ screen_opengl_render_doit(oglrender, rr);
}
RE_ReleaseResult(oglrender->re);
- /* update byte from float buffer */
ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
-
if (ibuf) {
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- /* write file for animation */
- if (oglrender->write_still) {
- char name[FILE_MAX];
- int ok;
-
- if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) {
- IMB_color_to_bw(ibuf);
- }
-
- BKE_image_path_from_imformat(
- name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
- ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */
- if (ok) printf("OpenGL Render written to '%s'\n", name);
- else printf("OpenGL Render failed to write '%s'\n", name);
- }
}
-
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
- if (rect)
- MEM_freeN(rect);
+ if (oglrender->write_still) {
+ screen_opengl_render_write(oglrender);
+ }
}
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
@@ -380,7 +538,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
- RenderResult *rr;
GPUOffScreen *ofs;
OGLRender *oglrender;
int sizex, sizey;
@@ -453,7 +610,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sseq = CTX_wm_space_seq(C);
}
-
oglrender->prevsa = prevsa;
oglrender->prevar = prevar;
@@ -487,15 +643,17 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create render result */
RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
- rr = RE_AcquireResultWrite(oglrender->re);
- if (rr->rectf == NULL)
- rr->rectf = MEM_callocN(sizeof(float) * 4 * sizex * sizey, "screen_opengl_render_init rect");
- RE_ReleaseResult(oglrender->re);
+ /* create render views */
+ screen_opengl_views_setup(oglrender);
/* wm vars */
oglrender->wm = wm;
oglrender->win = win;
+ oglrender->totvideos = 0;
+ oglrender->mh = NULL;
+ oglrender->movie_ctx_arr = NULL;
+
return true;
}
@@ -503,10 +661,19 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
{
Main *bmain = CTX_data_main(C);
Scene *scene = oglrender->scene;
+ size_t i;
if (oglrender->mh) {
- if (BKE_imtype_is_movie(scene->r.im_format.imtype))
- oglrender->mh->end_movie();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ for (i = 0; i < oglrender->totvideos; i++) {
+ oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
+ oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
+ }
+ }
+
+ if (oglrender->movie_ctx_arr) {
+ MEM_freeN(oglrender->movie_ctx_arr);
+ }
}
if (oglrender->timer) { /* exec will not have a timer */
@@ -547,13 +714,27 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender = op->customdata;
scene = oglrender->scene;
+ oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
oglrender->reports = op->reports;
- oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- if (!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports)) {
- screen_opengl_render_end(C, oglrender);
- return 0;
+ size_t i, width, height;
+
+ BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
+ oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
+ for (i = 0; i < oglrender->totvideos; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+
+ oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
+ if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex,
+ oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
+ {
+ screen_opengl_render_end(C, oglrender);
+ return 0;
+ }
}
}
@@ -563,18 +744,17 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return 1;
}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
OGLRender *oglrender = op->customdata;
Scene *scene = oglrender->scene;
- ImBuf *ibuf, *ibuf_save = NULL;
- void *lock;
char name[FILE_MAX];
bool ok = false;
const bool view_context = (oglrender->v3d != NULL);
- Object *camera = NULL;
bool is_movie;
+ RenderResult *rr;
/* go to next frame */
if (CFRA < oglrender->nfra)
@@ -594,7 +774,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (!is_movie) {
BKE_image_path_from_imformat(
name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
@@ -614,89 +794,41 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (BKE_scene_camera_switch_update(scene)) {
oglrender->v3d->camera = scene->camera;
}
-
- camera = oglrender->v3d->camera;
}
}
else {
BKE_scene_camera_switch_update(scene);
-
- camera = scene->camera;
}
/* render into offscreen buffer */
screen_opengl_render_apply(oglrender);
/* save to disk */
- ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
-
- if (ibuf) {
- bool needs_free = false;
-
- ibuf_save = ibuf;
-
- if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) {
- ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
-
- needs_free = true;
- }
-
- /* color -> grayscale */
- /* editing directly would alter the render view */
- if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
- ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save);
- IMB_color_to_bw(ibuf_bw);
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
-
- ibuf_save = ibuf_bw;
- }
- else {
- /* this is lightweight & doesnt re-alloc the buffers, only do this
- * to save the correct bit depth since the image is always RGBA */
- ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0);
-
- ibuf_cpy->rect = ibuf_save->rect;
- ibuf_cpy->rect_float = ibuf_save->rect_float;
- ibuf_cpy->zbuf_float = ibuf_save->zbuf_float;
-
- if (needs_free) {
- ibuf_cpy->mall = ibuf_save->mall;
- ibuf_save->mall = 0;
- IMB_freeImBuf(ibuf_save);
- }
+ rr = RE_AcquireResultRead(oglrender->re);
- ibuf_save = ibuf_cpy;
+ if (is_movie) {
+ ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
+ oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
+ if (ok) {
+ printf("Append frame %d", scene->r.cfra);
+ BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
}
-
- if (is_movie) {
- ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect,
- oglrender->sizex, oglrender->sizey, oglrender->reports);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
+ }
+ else {
+ BKE_render_result_stamp_info(scene, scene->camera, rr);
+ ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
+ if (ok) {
+ printf("Saved: %s", name);
+ BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
}
else {
- ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format);
-
- if (ok == 0) {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- else {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
+ printf("Write error: cannot save %s\n", name);
+ BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
}
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
}
- BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
+ RE_ReleaseResult(oglrender->re);
+
/* movie stats prints have no line break */
printf("\n");
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index 0d334082a2b..f98083f7e74 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -47,6 +47,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(OBJECT_OT_material_slot_select);
WM_operatortype_append(OBJECT_OT_material_slot_deselect);
WM_operatortype_append(OBJECT_OT_material_slot_copy);
+ WM_operatortype_append(OBJECT_OT_material_slot_move);
WM_operatortype_append(MATERIAL_OT_new);
WM_operatortype_append(TEXTURE_OT_new);
@@ -58,6 +59,9 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
+ WM_operatortype_append(SCENE_OT_render_view_add);
+ WM_operatortype_append(SCENE_OT_render_view_remove);
+
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 99edaff759e..9ed0cec5545 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -79,7 +79,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -128,7 +128,7 @@ ImBuf *get_brush_icon(Brush *brush)
}
if (brush->icon_imbuf)
- BKE_icon_changed(BKE_icon_getid(&brush->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
}
}
}
@@ -161,6 +161,7 @@ typedef struct ShaderPreview {
unsigned int *pr_rect;
int pr_method;
+ Main *bmain;
Main *pr_main;
} ShaderPreview;
@@ -171,6 +172,7 @@ typedef struct IconPreviewSize {
} IconPreviewSize;
typedef struct IconPreview {
+ Main *bmain;
Scene *scene;
void *owner;
ID *id;
@@ -261,12 +263,14 @@ static Scene *preview_get_scene(Main *pr_main)
/* call this with a pointer to initialize preview scene */
/* call this with NULL to restore assigned ID pointers in preview scene */
-static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPreview *sp)
+static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
Scene *sce;
Base *base;
Main *pr_main = sp->pr_main;
-
+
+ memcpy(pr_main->name, bmain->name, sizeof(pr_main->name));
+
sce = preview_get_scene(pr_main);
if (sce) {
@@ -423,7 +427,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
Tex *tex = NULL, *origtex = (Tex *)id;
if (origtex) {
- tex = localize_texture(origtex);
+ tex = BKE_texture_localize(origtex);
sp->texcopy = tex;
BLI_addtail(&pr_main->tex, tex);
}
@@ -525,6 +529,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
+ RenderView *rv;
RenderResult rres;
char name[32];
int offx = 0;
@@ -548,9 +553,16 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
/* test if something rendered ok */
re = RE_GetRender(name);
- RE_AcquireResultImage(re, &rres);
- if (rres.rectf) {
+ if (re == NULL)
+ return false;
+
+ RE_AcquireResultImageViews(re, &rres);
+
+ /* material preview only needs monoscopy (view 0) */
+ rv = RE_RenderViewGetById(&rres, 0);
+
+ if (rv->rectf) {
if (ABS(rres.rectx - newx) < 2 && ABS(rres.recty - newy) < 2) {
@@ -561,9 +573,11 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
+
+ /* material preview only needs monoscopy (view 0) */
if (re)
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
-
+ RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
+
glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
MEM_freeN(rect_byte);
@@ -573,7 +587,7 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
}
}
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImageViews(re, &rres);
return ok;
}
@@ -702,7 +716,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* get the stuff from the builtin preview dbase */
- sce = preview_prepare_scene(sp->scene, id, idtype, sp);
+ sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
if (sce == NULL) return;
if (!split || first) sprintf(name, "Preview %p", sp->owner);
@@ -757,7 +771,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main */
// if (idtype == ID_TE) {
@@ -925,65 +939,87 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
ShaderPreview *sp = customdata;
- ID *id = sp->id;
- short idtype = GS(id->name);
-
- if (idtype == ID_IM) {
- Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
- ImageUser iuser = {NULL};
- /* ima->ok is zero when Image cannot load */
- if (ima == NULL || ima->ok == 0)
- return;
+ if (sp->pr_method == PR_ICON_DEFERRED) {
+ PreviewImage *prv = sp->owner;
+ ImBuf *thumb;
+ char *deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = deferred_data[0];
+ char *path = &deferred_data[1];
- /* setup dummy image user */
- iuser.ok = iuser.framenr = 1;
- iuser.scene = sp->scene;
-
- /* elubie: this needs to be changed: here image is always loaded if not
- * already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
+// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
- *do_update = true;
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect);
+ IMB_freeImBuf(thumb);
+ }
}
- else if (idtype == ID_BR) {
- Brush *br = (Brush *)id;
+ else {
+ ID *id = sp->id;
+ short idtype = GS(id->name);
+
+ if (idtype == ID_IM) {
+ Image *ima = (Image *)id;
+ ImBuf *ibuf = NULL;
+ ImageUser iuser = {NULL};
+
+ /* ima->ok is zero when Image cannot load */
+ if (ima == NULL || ima->ok == 0)
+ return;
+
+ /* setup dummy image user */
+ iuser.ok = iuser.framenr = 1;
+ iuser.scene = sp->scene;
+
+ /* elubie: this needs to be changed: here image is always loaded if not
+ * already there. Very expensive for large images. Need to find a way to
+ * only get existing ibuf */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
- br->icon_imbuf = get_brush_icon(br);
+ icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+ *do_update = true;
- if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
- return;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ else if (idtype == ID_BR) {
+ Brush *br = (Brush *)id;
- icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+ br->icon_imbuf = get_brush_icon(br);
- *do_update = true;
- }
- else {
- /* re-use shader job */
- shader_preview_startjob(customdata, stop, do_update);
+ memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+
+ if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
+ return;
- /* world is rendered with alpha=0, so it wasn't displayed
- * this could be render option for sky to, for later */
- if (idtype == ID_WO) {
- set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+
+ *do_update = true;
}
- else if (idtype == ID_MA) {
- Material *ma = (Material *)id;
+ else {
+ /* re-use shader job */
+ shader_preview_startjob(customdata, stop, do_update);
- if (ma->material_type == MA_TYPE_HALO)
+ /* world is rendered with alpha=0, so it wasn't displayed
+ * this could be render option for sky to, for later */
+ if (idtype == ID_WO) {
set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
+ else if (idtype == ID_MA) {
+ Material *ma = (Material *)id;
+
+ if (ma->material_type == MA_TYPE_HALO)
+ set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
}
}
}
@@ -995,7 +1031,7 @@ static void common_preview_startjob(void *customdata, short *stop, short *do_upd
{
ShaderPreview *sp = customdata;
- if (sp->pr_method == PR_ICON_RENDER)
+ if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED))
icon_preview_startjob(customdata, stop, do_update);
else
shader_preview_startjob(customdata, stop, do_update);
@@ -1031,29 +1067,35 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
while (cur_size) {
+ PreviewImage *prv = ip->owner;
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ const bool is_render = !prv->use_deferred;
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
sp->sizey = cur_size->sizey;
- sp->pr_method = PR_ICON_RENDER;
+ sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
-
- if (use_new_shading) {
- /* texture icon rendering is hardcoded to use BI,
- * so don't even think of using cycle's bmain for
- * texture icons
- */
- if (GS(ip->id->name) != ID_TE)
- sp->pr_main = G_pr_main_cycles;
- else
+ sp->bmain = ip->bmain;
+
+ if (is_render) {
+ BLI_assert(ip->id);
+ if (use_new_shading) {
+ /* texture icon rendering is hardcoded to use BI,
+ * so don't even think of using cycle's bmain for
+ * texture icons
+ */
+ if (GS(ip->id->name) != ID_TE)
+ sp->pr_main = G_pr_main_cycles;
+ else
+ sp->pr_main = G_pr_main;
+ }
+ else {
sp->pr_main = G_pr_main;
- }
- else {
- sp->pr_main = G_pr_main;
+ }
}
common_preview_startjob(sp, stop, do_update, progress);
@@ -1098,12 +1140,13 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
-void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
{
IconPreview ip = {NULL};
short stop = false, update = false;
float progress = 0.0f;
+ ip.bmain = bmain;
ip.scene = scene;
ip.owner = id;
ip.id = id;
@@ -1134,8 +1177,9 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
/* customdata for preview thread */
+ ip->bmain = CTX_data_main(C);
ip->scene = CTX_data_scene(C);
- ip->owner = id;
+ ip->owner = owner;
ip->id = id;
icon_preview_add_size(ip, rect, sizex, sizey);
@@ -1175,6 +1219,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
sp->id = id;
sp->parent = parent;
sp->slot = slot;
+ sp->bmain = CTX_data_main(C);
/* hardcoded preview .blend for cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index ff90f48d705..3b8b874a462 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -41,8 +41,9 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLF_translation.h"
@@ -202,7 +203,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
if (nurbs) {
for (nu = nurbs->first; nu; nu = nu->next)
if (isNurbsel(nu))
- nu->mat_nr = nu->charidx = ob->actcol - 1;
+ nu->mat_nr = ob->actcol - 1;
}
}
else if (ob->type == OB_FONT) {
@@ -381,6 +382,74 @@ void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+static int material_slot_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+
+ unsigned int *slot_remap;
+ int index_pair[2];
+
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (!ob || ob->totcol < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* up */
+ if (dir == 1 && ob->actcol > 1) {
+ index_pair[0] = ob->actcol - 2;
+ index_pair[1] = ob->actcol - 1;
+ ob->actcol--;
+ }
+ /* down */
+ else if (dir == -1 && ob->actcol < ob->totcol) {
+ index_pair[0] = ob->actcol - 1;
+ index_pair[1] = ob->actcol - 0;
+ ob->actcol++;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
+
+ range_vn_u(slot_remap, ob->totcol, 0);
+
+ slot_remap[index_pair[0]] = index_pair[1];
+ slot_remap[index_pair[1]] = index_pair[0];
+
+ BKE_material_remap_object(ob, slot_remap);
+
+ MEM_freeN(slot_remap);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_material_slot_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem material_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Material";
+ ot->idname = "OBJECT_OT_material_slot_move";
+ ot->description = "Move the active material up/down in the list";
+
+ /* api callbacks */
+ ot->exec = material_slot_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
/********************** new material operator *********************/
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
@@ -450,7 +519,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
tex = BKE_texture_copy(tex);
}
else {
- tex = add_texture(bmain, DATA_("Texture"));
+ tex = BKE_texture_add(bmain, DATA_("Texture"));
}
/* hook into UI */
@@ -605,6 +674,70 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+/********************** render view operators *********************/
+
+static int render_view_remove_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* don't allow user to remove "left" and "right" views */
+ return scene->r.actview > 1;
+}
+
+static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ BKE_scene_add_render_view(scene, NULL);
+ scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Render View";
+ ot->idname = "SCENE_OT_render_view_add";
+ ot->description = "Add a render view";
+
+ /* api callbacks */
+ ot->exec = render_view_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+
+ if (!BKE_scene_remove_render_view(scene, rv))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Render View";
+ ot->idname = "SCENE_OT_render_view_remove";
+ ot->description = "Remove the selected render view";
+
+ /* api callbacks */
+ ot->exec = render_view_remove_exec;
+ ot->poll = render_view_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
#ifdef WITH_FREESTYLE
static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)
@@ -731,10 +864,11 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- BKE_freestyle_lineset_add(&srl->freestyleConfig, NULL);
+ BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, NULL);
DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -893,6 +1027,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
@@ -903,10 +1038,10 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
}
if (lineset->linestyle) {
lineset->linestyle->id.us--;
- lineset->linestyle = BKE_linestyle_copy(lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
else {
- lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
}
DAG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
@@ -1490,7 +1625,7 @@ static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
@@ -1533,7 +1668,7 @@ static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op))
for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->env)
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index be42e2ed518..dedcbb144aa 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -61,6 +61,7 @@
#include "ED_node.h"
#include "ED_render.h"
+#include "ED_view3d.h"
#include "render_intern.h" // own include
@@ -141,26 +142,19 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
recursive_check = false;
}
-void ED_render_engine_area_exit(ScrArea *sa)
+void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
{
/* clear all render engines in this area */
ARegion *ar;
+ wmWindowManager *wm = bmain->wm.first;
if (sa->spacetype != SPACE_VIEW3D)
return;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
-
if (ar->regiontype != RGN_TYPE_WINDOW || !(ar->regiondata))
continue;
-
- rv3d = ar->regiondata;
-
- if (rv3d->render_engine) {
- RE_engine_free(rv3d->render_engine);
- rv3d->render_engine = NULL;
- }
+ ED_view3d_stop_render_preview(wm, ar);
}
}
@@ -173,7 +167,7 @@ void ED_render_engine_changed(Main *bmain)
for (sc = bmain->screen.first; sc; sc = sc->id.next)
for (sa = sc->areabase.first; sa; sa = sa->next)
- ED_render_engine_area_exit(sa);
+ ED_render_engine_area_exit(bmain, sa);
RE_FreePersistentData();
@@ -276,7 +270,7 @@ static void material_changed(Main *bmain, Material *ma)
int texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
/* glsl */
if (ma->gpumaterial.first)
@@ -291,7 +285,7 @@ static void material_changed(Main *bmain, Material *ma)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&parent->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&parent->id));
if (parent->gpumaterial.first)
GPU_material_free(&parent->gpumaterial);
@@ -306,7 +300,7 @@ static void material_changed(Main *bmain, Material *ma)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -331,7 +325,7 @@ static void lamp_changed(Main *bmain, Lamp *la)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&la->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&la->id));
/* glsl */
for (ob = bmain->object.first; ob; ob = ob->id.next)
@@ -367,7 +361,7 @@ static void texture_changed(Main *bmain, Tex *tex)
bool texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&tex->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
/* paint overlays */
for (scene = bmain->scene.first; scene; scene = scene->id.next)
@@ -378,7 +372,7 @@ static void texture_changed(Main *bmain, Tex *tex)
if (!material_uses_texture(ma, tex))
continue;
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
if (ma->gpumaterial.first)
GPU_material_free(&ma->gpumaterial);
@@ -409,7 +403,7 @@ static void texture_changed(Main *bmain, Tex *tex)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&wo->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
if (wo->gpumaterial.first)
GPU_material_free(&wo->gpumaterial);
@@ -429,7 +423,7 @@ static void texture_changed(Main *bmain, Tex *tex)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -457,7 +451,7 @@ static void world_changed(Main *bmain, World *wo)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&wo->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
/* glsl */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
@@ -476,7 +470,7 @@ static void image_changed(Main *bmain, Image *ima)
Tex *tex;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
for (tex = bmain->tex.first; tex; tex = tex->id.next)
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index fe357a7a0e2..f6690296890 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -63,7 +63,7 @@ static ScrArea *biggest_non_image_area(bContext *C)
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->winx > 30 && sa->winy > 30) {
size = sa->winx * sa->winy;
- if (sa->spacetype == SPACE_BUTS) {
+ if (!sa->full && sa->spacetype == SPACE_BUTS) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
big = sa;
@@ -197,7 +197,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
if (sa->full) {
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
}
}
else {
@@ -245,6 +245,11 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
ScrArea *sa = CTX_wm_area(C);
SpaceImage *sima = sa->spacedata.first;
+ /* ensure image editor fullscreen and area fullscreen states are in sync */
+ if ((sima->flag & SI_FULLWINDOW) && !sa->full) {
+ sima->flag &= ~SI_FULLWINDOW;
+ }
+
/* test if we have a temp screen in front */
if (win->screen->temp) {
wm_window_lower(win);
@@ -256,10 +261,11 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
}
- else
+ else {
ED_area_prevspace(C, sa);
+ }
return OPERATOR_FINISHED;
}
@@ -320,7 +326,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wm
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
}
else if (sima->next) {
/* workaround for case of double prevspace, render window
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index c423d81bfe2..7fe6518134e 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -61,6 +61,9 @@
#include "BIF_glutil.h"
#include "BLF_api.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -149,6 +152,34 @@ void ED_area_do_refresh(bContext *C, ScrArea *sa)
}
/**
+ * Action zones are only updated if the mouse is inside of them, but in some cases (currently only fullscreen icon)
+ * it might be needed to update their properties and redraw if the mouse isn't inside.
+ */
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[2])
+{
+ AZone *az;
+ bool changed = false;
+
+ for (az = sa->actionzones.first; az; az = az->next) {
+ if (az->type == AZONE_FULLSCREEN) {
+ /* only if mouse is not hovering the azone */
+ if (BLI_rcti_isect_pt_v(&az->rect, mouse_xy) == false) {
+ az->alpha = 0.0f;
+ changed = true;
+
+ /* can break since currently only this is handled here */
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+ sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ ED_area_tag_redraw(sa);
+ }
+}
+
+/**
* \brief Corner widget use for quitting fullscreen.
*/
static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, float alpha)
@@ -366,6 +397,11 @@ static void region_draw_azone_tria(AZone *az)
glDisable(GL_BLEND);
}
+static void area_azone_tag_update(ScrArea *sa)
+{
+ sa->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
+}
+
static void region_draw_azones(ScrArea *sa, ARegion *ar)
{
AZone *az;
@@ -406,6 +442,10 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
}
else if (az->type == AZONE_FULLSCREEN) {
area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
+
+ if (az->alpha != 0.0f) {
+ area_azone_tag_update(sa);
+ }
}
}
}
@@ -493,7 +533,6 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
glDisable(GL_BLEND);
#endif
- ar->do_draw = 0;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
UI_blocklist_free_inactive(C, &ar->uiblocks);
@@ -773,7 +812,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2.5f * AZONEPAD_TAB_PLUSW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - 1.5f * AZONEPAD_TAB_PLUSW;
@@ -818,7 +857,7 @@ static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TABW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TABW;
@@ -863,7 +902,7 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TRIAW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TRIAW;
@@ -1224,16 +1263,22 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
ar->winrct = *remainder;
- if (alignment == RGN_ALIGN_TOP)
- ar->winrct.ymin = ar->winrct.ymax;
- else if (alignment == RGN_ALIGN_BOTTOM)
- ar->winrct.ymax = ar->winrct.ymin;
- else if (alignment == RGN_ALIGN_RIGHT)
- ar->winrct.xmin = ar->winrct.xmax;
- else if (alignment == RGN_ALIGN_LEFT)
- ar->winrct.xmax = ar->winrct.xmin;
- else /* prevent winrct to be valid */
- ar->winrct.xmax = ar->winrct.xmin;
+ switch (alignment) {
+ case RGN_ALIGN_TOP:
+ ar->winrct.ymin = ar->winrct.ymax;
+ break;
+ case RGN_ALIGN_BOTTOM:
+ ar->winrct.ymax = ar->winrct.ymin;
+ break;
+ case RGN_ALIGN_RIGHT:
+ ar->winrct.xmin = ar->winrct.xmax;
+ break;
+ case RGN_ALIGN_LEFT:
+ default:
+ /* prevent winrct to be valid */
+ ar->winrct.xmax = ar->winrct.xmin;
+ break;
+ }
}
/* restore prev-split exception */
@@ -2028,6 +2073,196 @@ void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_co
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
}
+#define MAX_METADATA_STR 1024
+
+static const char *meta_data_list[] =
+{
+ "File",
+ "Strip",
+ "Note",
+ "Date",
+ "RenderTime",
+ "Marker",
+ "Time",
+ "Frame",
+ "Camera",
+ "Scene"
+};
+
+BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset)
+{
+ return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]);
+}
+
+static void metadata_draw_imbuf(ImBuf *ibuf, rctf rect, int fontid, const bool is_top)
+{
+ char temp_str[MAX_METADATA_STR];
+ int line_width;
+ int ofs_y = 0;
+ short i;
+ int len;
+ const float height = BLF_height_max(fontid);
+ const float vertical_offset = height + (0.1f * U.widget_unit);
+
+ if (is_top) {
+ for (i = 0; i < 4; i++) {
+ /* first line */
+ if (i == 0) {
+ bool do_newline = false;
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ if (metadata_is_valid(ibuf, temp_str, 0, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ if (metadata_is_valid(ibuf, temp_str, 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect.xmax - line_width - (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ if (do_newline)
+ ofs_y += vertical_offset;
+ }
+ else if (i == 1) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ else {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect.xmax - line_width - (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ }
+ }
+ else {
+ int ofs_x = 0;
+ for (i = 5; i < 10; i++) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ if (metadata_is_valid(ibuf, temp_str, i, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit) + ofs_x,
+ rect.ymin + (0.3f * U.widget_unit), 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+
+ ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ }
+ }
+ }
+}
+
+static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
+{
+ char str[MAX_METADATA_STR] = "";
+ short i, count = 0;
+ const float height = BLF_height_max(fontid) + 0.1f * U.widget_unit;
+
+ if (is_top) {
+ if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) {
+ count++;
+ }
+ for (i = 2; i < 5; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count++;
+ }
+ }
+ }
+ else {
+ for (i = 5; i < 10; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count = 1;
+ }
+ }
+ }
+
+ if (count) {
+ return (height * count + (0.1f * U.widget_unit));
+ }
+
+ return 0;
+}
+
+#undef MAX_METADATA_STR
+
+void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float zoomx, float zoomy)
+{
+ float box_y;
+ rctf rect;
+ uiStyle *style = UI_style_get_dpi();
+
+ if (!ibuf->metadata)
+ return;
+
+ /* find window pixel coordinates of origin */
+ glPushMatrix();
+
+ /* offset and zoom using ogl */
+ glTranslatef(x, y, 0.0f);
+ glScalef(zoomx, zoomy, 1.0f);
+
+ BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f, U.dpi);
+
+ /* *** upper box*** */
+
+ /* get needed box height */
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, true);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymax, frame.ymax + box_y);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, rect, blf_mono_font, true);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+
+ /* *** lower box*** */
+
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, false);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up box rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymin - box_y, frame.ymin);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, rect, blf_mono_font, false);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+ glPopMatrix();
+}
+
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
{
float gridsize, gridstep = 1.0f / 32.0f;
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 6001534e88d..fd65d81baad 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -579,25 +579,25 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
continue;
if (type == GL_FLOAT) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
/* add an extra border of pixels so linear looks ok at edges of full image. */
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
glEnable(GL_TEXTURE_2D);
@@ -841,7 +841,7 @@ void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x
/**
* Translate the \a world point from world coordinates into screen space.
*/
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2])
{
screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
@@ -991,7 +991,7 @@ void bgl_get_mats(bglMats *mats)
/**
* \note \a viewdist is only for ortho at the moment.
*/
-void bglPolygonOffset(float viewdist, float dist)
+void bglPolygonOffset(float viewdist, float dist)
{
static float winmat[16], offset = 0.0;
@@ -1007,8 +1007,25 @@ void bglPolygonOffset(float viewdist, float dist)
/* dist is from camera to center point */
- if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist; // ortho tweaking
- else offs = 0.0005f * dist; // should be clipping value or so...
+ if (winmat[15] > 0.5f) {
+#if 1
+ offs = 0.00001f * dist * viewdist; // ortho tweaking
+#else
+ static float depth_fac = 0.0f;
+ if (depth_fac == 0.0f) {
+ int depthbits;
+ glGetIntegerv(GL_DEPTH_BITS, &depthbits);
+ depth_fac = 1.0f / (float)((1 << depthbits) - 1);
+ }
+ offs = (-1.0 / winmat[10]) * dist * depth_fac;
+
+ UNUSED_VARS(viewdist);
+#endif
+ }
+ else {
+ /* should be clipping value or so... */
+ offs = 0.0005f * dist;
+ }
winmat[14] -= offs;
offset += offs;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 3431ce9f50a..87c0ce398e5 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -47,6 +47,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_gpencil.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "RNA_access.h"
@@ -59,6 +60,18 @@
#include "screen_intern.h"
+static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx)
+{
+ /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */
+ if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) {
+ const unsigned int lay = BKE_screen_view3d_layer_all(sc);
+ if (lay) {
+ return lay;
+ }
+ }
+ return scene->lay;
+}
+
const char *screen_context_dir[] = {
"scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
@@ -81,7 +94,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ScrArea *sa = CTX_wm_area(C);
Scene *scene = sc->scene;
Base *base;
- unsigned int lay = scene->lay;
#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */
Object *obact = CTX_data_active_object(C);
@@ -102,10 +114,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int visible_objects = CTX_data_equals(member, "visible_objects");
for (base = scene->base.first; base; base = base->next) {
- if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & scene->lay)) {
+ if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
if (visible_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -116,6 +129,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selectable_objects = CTX_data_equals(member, "selectable_objects");
for (base = scene->base.first; base; base = base->next) {
@@ -132,10 +146,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_objects = CTX_data_equals(member, "selected_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if (selected_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -146,10 +161,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
if (0 == BKE_object_is_libdata(base->object)) {
if (selected_editable_objects)
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index aadfa9e6608..0c40c833c0d 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -59,6 +59,7 @@
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
+#include "ED_node.h"
#include "ED_render.h"
#include "UI_interface.h"
@@ -1747,7 +1748,9 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
newsa = sa;
}
}
-
+
+ BLI_assert(newsa);
+
if (sa && (sa->spacetype != type)) {
newsa->flag |= AREA_FLAG_TEMP_TYPE;
}
@@ -1760,11 +1763,18 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
return newsa;
}
-void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
+/**
+ * \a was_prev_temp for the case previous space was a temporary fullscreen as well
+ */
+void ED_screen_full_prevspace(bContext *C, ScrArea *sa, const bool was_prev_temp)
{
if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
/* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
ED_area_prevspace(C, sa);
+ /* only clear if previous space wasn't a temp fullscreen as well */
+ if (!was_prev_temp) {
+ sa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ }
}
else {
ED_screen_restore_temp_type(C, sa);
@@ -1799,13 +1809,12 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
if (sl->next) {
if (sa->flag & AREA_FLAG_TEMP_TYPE) {
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
}
else {
ED_screen_state_toggle(C, win, sa, state);
}
-
- sa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ /* warning: 'sa' may be freed */
}
/* otherwise just tile the area again */
else {
@@ -1813,7 +1822,11 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
}
}
-/* this function toggles: if area is maximized/full then the parent will be restored */
+/**
+ * this function toggles: if area is maximized/full then the parent will be restored
+ *
+ * \warning \a sa may be freed.
+ */
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
bScreen *sc, *oldscreen;
@@ -2118,4 +2131,85 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
}
+/*
+ * return true if any active area requires to see in 3D
+ */
+bool ED_screen_stereo3d_required(bScreen *screen)
+{
+ ScrArea *sa;
+ Scene *sce = screen->scene;
+ const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d;
+
+ if (!is_multiview)
+ continue;
+
+ v3d = sa->spacedata.first;
+ if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima;
+
+ /* images should always show in stereo, even if
+ * the file doesn't have views enabled */
+ sima = sa->spacedata.first;
+ if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
+ (sima->iuser.flag & IMA_SHOW_STEREO))
+ {
+ return true;
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode;
+
+ if (!is_multiview)
+ continue;
+
+ snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq;
+
+ if (!is_multiview)
+ continue;
+ sseq = sa->spacedata.first;
+ if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ return true;
+ }
+
+ if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
+ return true;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 79036d3356f..ccb6d5a6dca 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -32,8 +32,6 @@
#define __SCREEN_INTERN_H__
/* internal exports only */
-struct wmWindow;
-struct Scene;
#define AZONESPOT (0.6f * U.widget_unit)
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 48d39020236..e5c3cb4e5e2 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -81,6 +81,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "screen_intern.h" /* own module include */
@@ -717,7 +718,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
else
event.type = EVT_ACTIONZONE_REGION;
- event.val = 0;
+ event.val = KM_NOTHING;
event.customdata = op->customdata;
event.customdatafree = true;
op->customdata = NULL;
@@ -990,6 +991,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
newwin = WM_window_open(C, &rect);
+ *newwin->stereo3d_format = *win->stereo3d_format;
/* allocs new screen and adds to newly created window, using window size */
newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);
@@ -1928,6 +1930,12 @@ static void region_scale_validate_size(RegionMoveData *rmd)
static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
{
+ /* hidden areas may have bad 'View2D.cur' value,
+ * correct before displaying. see T45156 */
+ if (rmd->ar->flag & RGN_FLAG_HIDDEN) {
+ UI_view2d_curRect_validate(&rmd->ar->v2d);
+ }
+
region_toggle_hidden(C, rmd->ar, 0);
region_scale_validate_size(rmd);
}
@@ -2099,7 +2107,7 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, false);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2151,7 +2159,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -2257,7 +2265,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
else {
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2319,7 +2327,7 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -3413,10 +3421,17 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 0;
}
+//#define PROFILE_AUDIO_SYNCH
+
static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
+#ifdef PROFILE_AUDIO_SYNCH
+ static int old_frame = 0;
+ int newfra_int;
+#endif
+
if (screen->animtimer && screen->animtimer == event->customdata) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -3435,14 +3450,27 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if ((scene->audio.flag & AUDIO_SYNC) &&
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
- finite(time = sound_sync_scene(scene)))
+ finite(time = BKE_sound_sync_scene(scene)))
{
double newfra = (double)time * FPS;
+
/* give some space here to avoid jumps */
if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra)
scene->r.cfra++;
else
scene->r.cfra = newfra + 0.5;
+
+#ifdef PROFILE_AUDIO_SYNCH
+ newfra_int = scene->r.cfra;
+ if (newfra_int < old_frame) {
+ printf("back jump detected, frame %d!\n", newfra_int);
+ }
+ else if (newfra_int > old_frame + 1) {
+ printf("forward jump detected, frame %d!\n", newfra_int);
+ }
+ fflush(stdout);
+ old_frame = newfra_int;
+#endif
}
else {
if (sync) {
@@ -3509,8 +3537,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
sad->flag |= ANIMPLAY_FLAG_JUMPED;
}
- if (sad->flag & ANIMPLAY_FLAG_JUMPED)
- sound_seek_scene(bmain, scene);
+ if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
+ BKE_sound_seek_scene(bmain, scene);
+#ifdef PROFILE_AUDIO_SYNCH
+ old_frame = CFRA;
+#endif
+ }
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
ED_update_for_newframe(bmain, scene, 1);
@@ -3610,7 +3642,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0, 0);
- sound_stop_scene(scene);
+ BKE_sound_stop_scene(scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -3618,7 +3650,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) /* XXX only play audio forwards!? */
- sound_play_scene(scene);
+ BKE_sound_play_scene(scene);
ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
@@ -3775,7 +3807,7 @@ static int fullscreen_back_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, sa, false);
return OPERATOR_FINISHED;
}
@@ -4227,6 +4259,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
+ RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
/* area move after action zones */
WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
@@ -4254,8 +4288,6 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", F10KEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 9c05f1d4780..3f66d84c185 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -303,6 +303,9 @@ typedef struct ScreenshotJob {
const short *stop;
const short *do_update;
ReportList reports;
+
+ bMovieHandle *movie_handle;
+ void *movie_ctx;
} ScreenshotJob;
@@ -312,7 +315,13 @@ static void screenshot_freejob(void *sjv)
if (sj->dumprect)
MEM_freeN(sj->dumprect);
-
+
+ if (sj->movie_handle) {
+ bMovieHandle *mh = sj->movie_handle;
+ mh->end_movie(sj->movie_ctx);
+ mh->context_free(sj->movie_ctx);
+ }
+
MEM_freeN(sj);
}
@@ -337,20 +346,22 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
{
ScreenshotJob *sj = sjv;
RenderData rd = sj->scene->r;
- bMovieHandle *mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
-
+ bMovieHandle *mh = NULL;
+
/* we need this as local variables for renderdata */
rd.frs_sec = U.scrcastfps;
rd.frs_sec_base = 1.0f;
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
- if (!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
+ mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
+ sj->movie_ctx = mh->context_create();
+ sj->movie_handle = mh;
+
+ if (!mh->start_movie(sj->movie_ctx, sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports, false, "")) {
printf("screencast job stopped\n");
return;
}
}
- else
- mh = NULL;
sj->stop = stop;
sj->do_update = do_update;
@@ -362,8 +373,8 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
if (sj->dumprect) {
if (mh) {
- if (mh->append_movie(&rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
- sj->dumpsx, sj->dumpsy, &sj->reports))
+ if (mh->append_movie(sj->movie_ctx, &rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
+ sj->dumpsx, sj->dumpsy, "", &sj->reports))
{
BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", rd.cfra);
printf("Appended frame %d\n", rd.cfra);
@@ -379,7 +390,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
BKE_image_path_from_imformat(
name, rd.pic, sj->bmain->name, rd.cfra,
- &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
+ &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL);
ibuf->rect = sj->dumprect;
ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
@@ -410,8 +421,11 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
PIL_sleep_ms(U.scrcastwait);
}
- if (mh)
- mh->end_movie();
+ if (mh) {
+ mh->end_movie(sj->movie_ctx);
+ mh->context_free(sj->movie_ctx);
+ sj->movie_handle = NULL;
+ }
BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 886e4e5ef8c..e4cad389004 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -426,7 +426,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
len = sqrtf(x * x + y * y);
if (len <= 1) {
- float avg = BKE_brush_curve_strength(br, len, 1.0f); /* Falloff curve */
+ float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
buffer[index] = 255 - (GLubyte)(255 * avg);
@@ -955,21 +955,32 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewCon
}
}
+static bool ommit_cursor_drawing(Paint *paint, PaintMode mode, Brush *brush)
+{
+ if (paint->flags & PAINT_SHOW_BRUSH) {
+ if (ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) && brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
ViewContext vc;
- PaintMode mode;
float final_radius;
float translation[2];
float outline_alpha, *outline_col;
float zoomx, zoomy;
-
+
/* check that brush drawing is enabled */
- if (!(paint->flags & PAINT_SHOW_BRUSH))
+ if (ommit_cursor_drawing(paint, mode, brush))
return;
/* can't use stroke vc here because this will be called during
@@ -978,7 +989,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
get_imapaint_zoom(C, &zoomx, &zoomy);
zoomx = max_ff(zoomx, zoomy);
- mode = BKE_paintmode_get_active_from_context(C);
/* skip everything and draw brush here */
if (brush->flag & BRUSH_CURVE) {
@@ -1018,8 +1028,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) ^
- !(brush->flag & BRUSH_DIR_IN)) &&
+ 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))
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 439c2a639bd..8c754d7adf3 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -222,6 +222,28 @@ static int paintcurve_point_co_index(char sel)
return i;
}
+static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
+{
+ /* when matching, guess based on endpoint side */
+ if (BEZSELECTED(bezt)) {
+ if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
+ return is_first ? SEL_F1 : SEL_F3;
+ }
+ else if (bezt->f1 & SELECT) {
+ return SEL_F1;
+ }
+ else if (bezt->f3 & SELECT) {
+ return SEL_F3;
+ }
+ else {
+ return fallback;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
/******************* Operators *********************************/
static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
@@ -295,10 +317,17 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
for (i = 0; i < pc->tot_points; i++) {
pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
}
- pcp[add_index].bez.f3 = SELECT;
- pcp[add_index].bez.h2 = HD_ALIGN;
- pc->add_index = add_index + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
+
+ if (pc->add_index != 0) {
+ pcp[add_index].bez.f3 = SELECT;
+ pcp[add_index].bez.h2 = HD_ALIGN;
+ }
+ else {
+ pcp[add_index].bez.f1 = SELECT;
+ pcp[add_index].bez.h1 = HD_ALIGN;
+ }
WM_paint_cursor_tag_redraw(window, ar);
}
@@ -384,7 +413,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
points_new[j] = pc->points[i];
if ((i + 1) == pc->add_index) {
- pc->add_index = j + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, j);
}
j++;
}
@@ -469,7 +498,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
if (pcp) {
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
if (selflag == SEL_F2) {
if (extend)
@@ -599,9 +628,8 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
pcp = NULL;
/* just find first selected point */
for (i = 0; i < pc->tot_points; i++) {
- if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) {
+ if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
pcp = &pc->points[i];
- select = SEL_F3;
break;
}
}
@@ -631,7 +659,7 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* only select the active point */
PAINT_CURVE_POINT_SELECT(pcp, psd->select);
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
WM_event_add_modal_handler(C, op);
WM_paint_cursor_tag_redraw(window, ar);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index f1c91d0fcb5..52a60347f9f 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -150,7 +150,7 @@ static void partialvis_update_grids(Object *ob,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node,
&grid_indices, &totgrid, NULL, NULL,
- &grids, NULL);
+ &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_get_grid_key(pbvh, &key);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 5cfbd164153..346be5b336e 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -215,7 +215,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
return NULL;
}
-void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -226,7 +226,7 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
/* check if tile is already pushed */
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (!proj) {
+ if (find_prev) {
data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
if (data)
return data;
@@ -445,7 +445,7 @@ void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int
*ty = (y >> IMAPAINT_TILE_BITS);
}
-void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@@ -474,7 +474,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -499,7 +499,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
+ GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
}
}
@@ -1393,7 +1393,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
if (ma && ma->texpaintslot)
ima = ma->texpaintslot[ma->paint_active_slot].ima;
}
- else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
ima = imapaint->canvas;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index eb96d1d20d5..483bf0f3190 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -359,7 +359,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d
float xy[2] = {x + xoff, y + yoff};
float len = len_v2(xy);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength(brush, len, radius));
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
}
}
@@ -889,7 +889,7 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb);
+ outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
if (fabsf(outrgb[0]) > threshold) {
float mask = BKE_brush_alpha_get(s->scene, s->brush);
float alpha = rgba[3];
@@ -996,8 +996,8 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
@@ -1049,7 +1049,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image, s->canvas,
region[a].destx, region[a].desty,
- region[a].width, region[a].height);
+ region[a].width, region[a].height, true);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
@@ -1109,7 +1109,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
if (ima == NULL) {
return 0;
}
- else if (ima->packedfile && ima->rr) {
+ else if (BKE_image_has_packedfile(ima) && ima->rr) {
s->warnpackedfile = ima->id.name + 2;
return 0;
}
@@ -1306,12 +1306,12 @@ static void paint_2d_fill_add_pixel_byte(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
float color_f[4];
@@ -1329,12 +1329,12 @@ static void paint_2d_fill_add_pixel_float(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) {
@@ -1386,21 +1386,21 @@ void paint_2d_bucket_fill(
if (!mouse_init || !br) {
/* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f);
+ blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
}
}
}
else {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b);
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
}
}
}
@@ -1410,7 +1410,7 @@ void paint_2d_bucket_fill(
* value is within the brush fill threshold from the fill color */
BLI_Stack *stack;
BLI_bitmap *touched;
- int coordinate;
+ size_t coordinate;
int width = ibuf->x;
float image_init[2];
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
@@ -1428,12 +1428,12 @@ void paint_2d_bucket_fill(
}
/* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
- stack = BLI_stack_new(sizeof(int), __func__);
- touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap");
+ stack = BLI_stack_new(sizeof(size_t), __func__);
+ touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
- coordinate = (y_px * ibuf->x + x_px);
+ coordinate = (((size_t)y_px) * ibuf->x + x_px);
if (do_float) {
copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
@@ -1566,7 +1566,7 @@ void paint_2d_gradient_fill(
do_float = (ibuf->rect_float != NULL);
/* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -1590,8 +1590,8 @@ void paint_2d_gradient_fill(
/* convert to premultiplied */
mul_v3_fl(color_f, color_f[3]);
color_f[3] *= br->alpha;
- IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
color_f, br->blend);
}
}
@@ -1619,8 +1619,8 @@ void paint_2d_gradient_fill(
linearrgb_to_srgb_v3_v3(color_f, color_f);
rgba_float_to_uchar((unsigned char *)&color_b, color_f);
((unsigned char *)&color_b)[3] *= br->alpha;
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
(unsigned char *)&color_b, br->blend);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 098f0d04d78..1549c31baf6 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_math_color_blend.h"
#include "BLI_memarena.h"
#include "BLI_threads.h"
@@ -134,6 +135,8 @@ BLI_INLINE unsigned char f_to_char(const float val)
//#define PROJ_DEBUG_PRINT_CLIP 1
#define PROJ_DEBUG_WINCLIP 1
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
/* projectFaceSeamFlags options */
//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
@@ -151,6 +154,13 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_FACE_WINDING_INIT 1
#define PROJ_FACE_WINDING_CW 2
+/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
+ * as this number approaches 1.0f the likelihood increases of float precision errors where
+ * it is occluded by an adjacent face */
+#define PROJ_FACE_SCALE_SEAM 0.99f
+#endif /* PROJ_DEBUG_NOSEAMBLEED */
+
+
#define PROJ_SRC_VIEW 1
#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
@@ -159,12 +169,6 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_VIEW_DATA_ID "view_data"
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
-
-/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
- * as this number approaches 1.0f the likelihood increases of float precision errors where
- * it is occluded by an adjacent face */
-#define PROJ_FACE_SCALE_SEAM 0.99f
-
#define PROJ_BUCKET_NULL 0
#define PROJ_BUCKET_INIT (1 << 0)
// #define PROJ_BUCKET_CLONE_INIT (1<<1)
@@ -190,9 +194,32 @@ typedef struct ProjPaintImage {
unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket.
* Here we store the mask rectangle */
bool **valid; /* store flag to enforce validation of undo rectangle */
- int touch;
+ bool touch;
} ProjPaintImage;
+/**
+ * Handle for stroke (operator customdata)
+ */
+typedef struct ProjStrokeHandle {
+ /* Support for painting from multiple views at once,
+ * currently used to impliment summetry painting,
+ * we can assume at least the first is set while painting. */
+ struct ProjPaintState *ps_views[8];
+ int ps_views_tot;
+ int symmetry_flags;
+
+ int orig_brush_size;
+
+ bool need_redraw;
+
+ /* trick to bypass regular paint and allow clone picking */
+ bool is_clone_cursor_pick;
+
+ /* In ProjPaintState, only here for convenience */
+ Scene *scene;
+ Brush *brush;
+} ProjStrokeHandle;
+
/* Main projection painting struct passed to all projection painting functions */
typedef struct ProjPaintState {
View3D *v3d;
@@ -208,24 +235,14 @@ typedef struct ProjPaintState {
Brush *brush;
short tool, blend, mode;
- int orig_brush_size;
+
float brush_size;
Object *ob;
+ /* for symmetry, we need to store modified object matrix */
+ float obmat[4][4];
+ float obmat_imat[4][4];
/* end similarities with ImagePaintState */
- DerivedMesh *dm;
- int dm_totface;
- int dm_totedge;
- int dm_totvert;
- int dm_release;
-
- MVert *dm_mvert;
- MEdge *dm_medge;
- MFace *dm_mface;
- MTFace **dm_mtface;
- MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
- MTFace *dm_mtface_stencil;
-
Image *stencil_ima;
Image *canvas_ima;
Image *clone_ima;
@@ -236,24 +253,16 @@ typedef struct ProjPaintState {
LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
unsigned char *bucketFlags; /* store if the bucks have been initialized */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
- char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
- float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
- LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
-#endif
+
char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
int buckets_y;
- ProjPaintImage *projImages;
-
int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
int image_tot; /* size of projectImages array */
float (*screenCoords)[4]; /* verts projected into floating point screen space */
- float *cavities; /* cavity amount for vertices */
float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
float screenMax[2];
float screen_width; /* Calculated from screenMin & screenMax */
@@ -272,12 +281,15 @@ typedef struct ProjPaintState {
bool do_mask_normal; /* mask out pixels based on their normals */
bool do_mask_cavity; /* mask out pixels based on cavity */
bool do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
- float normal_angle; /* what angle to mask at*/
+ float normal_angle; /* what angle to mask at */
+ float normal_angle__cos; /* cos(normal_angle), faster to compare */
float normal_angle_inner;
+ float normal_angle_inner__cos;
float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
bool do_face_sel; /* quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
bool is_ortho;
+ bool is_flip_object; /* the object is negative scaled */
bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
bool is_texbrush; /* only to avoid running */
bool is_maskbrush; /* mask brush is applied before masking */
@@ -302,13 +314,51 @@ typedef struct ProjPaintState {
int bucketMax[2];
int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
- /* redraw */
- bool need_redraw;
-
struct CurveMapping *cavity_curve;
BlurKernel *blurkernel;
+
+
+ /* -------------------------------------------------------------------- */
+ /* Vars shared between multiple views (keep last) */
+ /**
+ * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
+ * all other views re-use the data.
+ */
+
+#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
+ MEMCPY_STRUCT_OFS(ps_dst, ps_src, is_shared_user)
+
+#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) \
+ MEMSET_STRUCT_OFS(ps, 0, is_shared_user)
+
+ bool is_shared_user;
+
+ ProjPaintImage *projImages;
+ float *cavities; /* cavity amount for vertices */
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
+ char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
+ float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
+ LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
+#endif
+
SpinLock *tile_lock;
+
+ DerivedMesh *dm;
+ int dm_totface;
+ int dm_totedge;
+ int dm_totvert;
+ int dm_release;
+
+ MVert *dm_mvert;
+ MEdge *dm_medge;
+ MFace *dm_mface;
+ MTFace *dm_mtface_stencil;
+
+ MTFace **dm_mtface;
+ MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
} ProjPaintState;
typedef union pixelPointer {
@@ -326,25 +376,27 @@ typedef union pixelStore {
typedef struct ProjPixel {
float projCoSS[2]; /* the floating point screen projection of this pixel */
float worldCoSS[3];
+
+ short x_px, y_px;
+
+ unsigned short image_index; /* if anyone wants to paint onto more than 65535 images they can bite me */
+ unsigned char bb_cell_index;
+
+ /* for various reasons we may want to mask out painting onto this pixel */
+ unsigned short mask;
+
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
* new mask value is lower then mask_accum */
unsigned short *mask_accum;
- /* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
-
- short x_px, y_px;
/* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */
bool *valid;
PixelPointer origColor;
PixelStore newColor;
PixelPointer pixel;
-
- short image_index; /* if anyone wants to paint onto more than 32768 images they can bite me */
- unsigned char bb_cell_index;
} ProjPixel;
typedef struct ProjPixelClone {
@@ -474,7 +526,9 @@ static float VecZDepthPersp(
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3], int *side)
+static int project_paint_PickFace(
+ const ProjPaintState *ps, const float pt[2],
+ float w[3], int *r_side)
{
LinkNode *node;
float w_tmp[3];
@@ -531,7 +585,7 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
}
}
- *side = best_side;
+ *r_side = best_side;
return best_face_index; /* will be -1 or a valid face */
}
@@ -718,7 +772,7 @@ static bool project_bucket_point_occluded(
int face_index;
int isect_ret;
float w[3]; /* not needed when clipping */
- const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+ const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
/* we could return 0 for 1 face buckets, as long as this function assumes
* that the point its testing is only every originated from an existing face */
@@ -776,11 +830,11 @@ static int line_isect_y(const float p1[2], const float p2[2], const float y_leve
}
if (p1[1] > y_level && p2[1] < y_level) {
- *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/
+ *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /* (p1[1] - p2[1]); */
return ISECT_TRUE;
}
else if (p1[1] < y_level && p2[1] > y_level) {
- *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/
+ *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /* (p2[1] - p1[1]); */
return ISECT_TRUE;
}
else {
@@ -809,11 +863,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
}
if (p1[0] > x_level && p2[0] < x_level) {
- *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/
+ *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /* (p1[0] - p2[0]); */
return ISECT_TRUE;
}
else if (p1[0] < x_level && p2[0] > x_level) {
- *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/
+ *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /* (p2[0] - p1[0]); */
return ISECT_TRUE;
}
else {
@@ -1228,22 +1282,22 @@ static void screen_px_from_persp(
static void project_face_pixel(
const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
- int side, unsigned char rgba_ub[4], float rgba_f[4])
+ bool side, unsigned char rgba_ub[4], float rgba_f[4])
{
const float *uvCo1, *uvCo2, *uvCo3;
float uv_other[2], x, y;
- uvCo1 = (float *)tf_other->uv[0];
+ uvCo1 = tf_other->uv[0];
if (side == 1) {
- uvCo2 = (float *)tf_other->uv[2];
- uvCo3 = (float *)tf_other->uv[3];
+ uvCo2 = tf_other->uv[2];
+ uvCo3 = tf_other->uv[3];
}
else {
- uvCo2 = (float *)tf_other->uv[1];
- uvCo3 = (float *)tf_other->uv[2];
+ uvCo2 = tf_other->uv[1];
+ uvCo3 = tf_other->uv[2];
}
- interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w);
+ interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, w);
/* use */
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
@@ -1262,7 +1316,7 @@ static void project_face_pixel(
static float project_paint_uvpixel_mask(
const ProjPaintState *ps,
const int face_index,
- const int side,
+ const bool side,
const float w[3])
{
float mask;
@@ -1327,7 +1381,7 @@ static float project_paint_uvpixel_mask(
/* calculate mask */
if (ps->do_mask_normal) {
MFace *mf = &ps->dm_mface[face_index];
- float no[3], angle;
+ float no[3], angle_cos;
if (mf->flag & ME_SMOOTH) {
const short *no1, *no2, *no3;
no1 = ps->dm_mvert[mf->v1].no;
@@ -1366,9 +1420,13 @@ static float project_paint_uvpixel_mask(
#endif
}
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
+
/* now we can use the normal as a mask */
if (ps->is_ortho) {
- angle = angle_normalized_v3v3(ps->viewDir, no);
+ angle_cos = dot_v3v3(ps->viewDir, no);
}
else {
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
@@ -1389,15 +1447,18 @@ static float project_paint_uvpixel_mask(
viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
normalize_v3(viewDirPersp);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
- angle = angle_normalized_v3v3(viewDirPersp, no);
+ angle_cos = dot_v3v3(viewDirPersp, no);
}
- if (angle >= ps->normal_angle) {
+ if (angle_cos <= ps->normal_angle__cos) {
return 0.0f; /* outsize the normal limit*/
}
- else if (angle > ps->normal_angle_inner) {
- mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
+ else if (angle_cos < ps->normal_angle_inner__cos) {
+ mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
} /* otherwise no mask normal is needed, were within the limit */
}
@@ -1440,10 +1501,10 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
if (generate_tile) {
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
}
else {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true, false);
}
pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
@@ -1470,7 +1531,7 @@ static ProjPixel *project_paint_uvpixel_init(
const int face_index,
const float pixelScreenCo[4],
const float world_spaceCo[3],
- const int side,
+ const bool side,
const float w[3])
{
ProjPixel *projPixel;
@@ -1591,7 +1652,7 @@ static ProjPixel *project_paint_uvpixel_init(
}
else {
float co[2];
- sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
+ sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
/* no need to initialize the bucket, we're only checking buckets faces and for this
* the faces are already initialized in project_paint_delayed_face_init(...) */
@@ -1619,13 +1680,14 @@ static ProjPixel *project_paint_uvpixel_init(
}
static bool line_clip_rect2f(
+ const rctf *cliprect,
const rctf *rect,
const float l1[2], const float l2[2],
float l1_clip[2], float l2_clip[2])
{
/* first account for horizontal, then vertical lines */
/* horiz */
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its Y axis? */
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
return 0;
@@ -1636,7 +1698,7 @@ static bool line_clip_rect2f(
}
- if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1653,7 +1715,7 @@ static bool line_clip_rect2f(
CLAMP(l2_clip[0], rect->xmin, rect->xmax);
return 1;
}
- else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
+ else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its X axis? */
if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
return 0;
@@ -1664,7 +1726,7 @@ static bool line_clip_rect2f(
return 0;
}
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1703,7 +1765,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* top/bottom */
- if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] < l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymin;
@@ -1718,7 +1780,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] > l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymax;
@@ -1734,7 +1796,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* left/right */
- if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] < l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmin;
l1_clip[1] = isect;
@@ -1749,7 +1811,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] > l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmax;
l1_clip[1] = isect;
@@ -1964,7 +2026,7 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
- return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
+ return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
}
#endif
@@ -1976,7 +2038,10 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
#define ISECT_ALL4 ((1 << 4) - 1)
/* limit must be a fraction over 1.0f */
-static bool IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
+static bool IsectPT2Df_limit(
+ const float pt[2],
+ const float v1[2], const float v2[2], const float v3[2],
+ const float limit)
{
return ((area_tri_v2(pt, v1, v2) +
area_tri_v2(pt, v2, v3) +
@@ -2043,9 +2108,10 @@ static bool line_rect_clip(
static void project_bucket_clip_face(
- const bool is_ortho,
+ const bool is_ortho, const bool is_flip_object,
+ const rctf *cliprect,
const rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
+ const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[8][2],
int *tot, bool cull)
@@ -2071,7 +2137,8 @@ static void project_bucket_clip_face(
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
if (inside_bucket_flag == ISECT_ALL3) {
- flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
+ /* is_flip_object is used here because we use the face winding */
+ flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
(line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
/* all screenspace points are inside the bucket bounding box,
@@ -2193,7 +2260,7 @@ static void project_bucket_clip_face(
float cent[2] = {0.0f, 0.0f};
/*float up[2] = {0.0f, 1.0f};*/
int i;
- short doubles;
+ bool doubles;
(*tot) = 0;
@@ -2207,21 +2274,21 @@ static void project_bucket_clip_face(
if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
- if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
- if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
- if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
@@ -2404,7 +2471,7 @@ static bool IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
{
int i;
- int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
+ bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
for (i = 1; i < tot; i++) {
if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
@@ -2423,7 +2490,8 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
static void project_paint_face_init(
const ProjPaintState *ps,
const int thread_index, const int bucket_index, const int face_index, const int image_index,
- const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
+ const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
+ const bool clamp_u, const bool clamp_v)
{
/* Projection vars, to get the 3D locations into screen space */
MemArena *arena = ps->arena_mt[thread_index];
@@ -2448,8 +2516,8 @@ static void project_paint_face_init(
float mask;
float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
- int side;
- float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+ bool side;
+ const float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
float *vCo[4]; /* vertex screenspace coords */
@@ -2468,11 +2536,10 @@ static void project_paint_face_init(
int has_x_isect = 0, has_isect = 0; /* for early loop exit */
- int i1, i2, i3;
-
float uv_clip[8][2];
int uv_clip_tot;
const bool is_ortho = ps->is_ortho;
+ const bool is_flip_object = ps->is_flip_object;
const bool do_backfacecull = ps->do_backfacecull;
const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
@@ -2517,6 +2584,8 @@ static void project_paint_face_init(
}
do {
+ int i1, i2, i3;
+
if (side == 1) {
i1 = 0; i2 = 2; i3 = 3;
}
@@ -2534,11 +2603,12 @@ static void project_paint_face_init(
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
project_bucket_clip_face(
- is_ortho, bucket_bounds,
+ is_ortho, is_flip_object,
+ clip_rect, bucket_bounds,
v1coSS, v2coSS, v3coSS,
uv1co, uv2co, uv3co,
uv_clip, &uv_clip_tot,
- ps->do_backfacecull || ps->do_occlude);
+ do_backfacecull || ps->do_occlude);
/* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
#if 0
@@ -2674,7 +2744,7 @@ static void project_paint_face_init(
int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
float seam_subsection[4][2];
- float fac1, fac2, ftot;
+ float fac1, fac2;
if (outset_uv[0][0] == FLT_MAX) /* first time initialize */
uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0, (ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_CW) == 0);
@@ -2706,19 +2776,16 @@ static void project_paint_face_init(
else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
- line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
+ line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
{
-
- ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
-
- if (ftot > 0.0f) { /* avoid div by zero */
+ if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) { /* avoid div by zero */
if (mf->v4) {
- if (fidx1 == 2 || fidx2 == 2) side = 1;
+ if (fidx1 == 3 || fidx2 == 3) side = 1;
else side = 0;
}
- fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
- fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
+ fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
+ fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
@@ -2760,11 +2827,8 @@ static void project_paint_face_init(
/* Since this is a seam we need to work out where on the line this pixel is */
//fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]);
-
- fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]);
- if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); }
- else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); }
- else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
+ fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
+ interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
if (!is_ortho) {
pixelScreenCo[3] = 1.0f;
@@ -2779,24 +2843,20 @@ static void project_paint_face_init(
{
/* Only bother calculating the weights if we intersect */
if (ps->do_mask_normal || ps->dm_mtface_clone) {
-#if 1
+ const float uv_fac = fac1 + (fac * (fac2 - fac1));
+#if 0
/* get the UV on the line since we want to copy the pixels from there for bleeding */
float uv_close[2];
- float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]);
- if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]);
- else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]);
-
+ interp_v2_v2v2(uv_close, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], uv_fac);
if (side) {
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w);
}
else {
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w);
}
-#else /* this is buggy with quads, don't use for now */
+#else
/* Cheat, we know where we are along the edge so work out the weights from that */
- uv_fac = fac1 + (uv_fac * (fac2 - fac1));
-
w[0] = w[1] = w[2] = 0.0;
if (side) {
w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac;
@@ -2811,8 +2871,8 @@ static void project_paint_face_init(
/* a pity we need to get the worldspace pixel location here */
if (do_clip || do_3d_mapping) {
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+ if (side) interp_v3_v3v3v3(wco, vCo[0], vCo[2], vCo[3], w);
+ else interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
continue; /* Watch out that no code below this needs to run */
@@ -2851,6 +2911,8 @@ static void project_paint_face_init(
}
}
}
+#else
+ UNUSED_VARS(vCo, threaded);
#endif // PROJ_DEBUG_NOSEAMBLEED
}
@@ -2887,7 +2949,7 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *bucket_bounds)
+static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *clip_rect, const rctf *bucket_bounds)
{
LinkNode *node;
int face_index, image_index = 0;
@@ -2902,7 +2964,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
ima = ps->projImages[0].ima;
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
else {
@@ -2926,7 +2991,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
}
/* context switching done */
- project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, face_index, image_index,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
@@ -3078,7 +3146,8 @@ static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
}
}
-static void proj_paint_state_viewport_init(ProjPaintState *ps)
+static void proj_paint_state_viewport_init(
+ ProjPaintState *ps, const char symmetry_flag)
{
float mat[3][3];
float viewmat[4][4];
@@ -3088,7 +3157,19 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
ps->viewDir[1] = 0.0f;
ps->viewDir[2] = 1.0f;
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ copy_m4_m4(ps->obmat, ps->ob->obmat);
+
+ if (symmetry_flag) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if ((symmetry_flag >> i) & 1) {
+ negate_v3(ps->obmat[i]);
+ ps->is_flip_object = !ps->is_flip_object;
+ }
+ }
+ }
+
+ invert_m4_m4(ps->obmat_imat, ps->obmat);
if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
/* normal drawing */
@@ -3098,7 +3179,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
copy_m4_m4(viewmat, ps->rv3d->viewmat);
copy_m4_m4(viewinv, ps->rv3d->viewinv);
- ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
+ ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
}
@@ -3151,24 +3232,27 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
}
/* same as #ED_view3d_ob_project_mat_get */
- mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
+ mul_m4_m4m4(vmat, viewmat, ps->obmat);
mul_m4_m4m4(ps->projectMat, winmat, vmat);
}
/* viewDir - object relative */
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
copy_m3_m4(mat, viewinv);
mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->ob->imat);
+ copy_m3_m4(mat, ps->obmat_imat);
mul_m3_v3(mat, ps->viewDir);
normalize_v3(ps->viewDir);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(ps->viewDir);
+ }
+
/* viewPos - object relative */
copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->ob->imat);
+ copy_m3_m4(mat, ps->obmat_imat);
mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->ob->imat[3]);
+ add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
}
static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
@@ -3234,6 +3318,8 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
+#else
+ UNUSED_VARS(diameter);
#endif
}
else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
@@ -3313,12 +3399,14 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
if (reset_threads)
ps->thread_tot = 1;
- if (ps->thread_tot > 1) {
- ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
- BLI_spin_init(ps->tile_lock);
- }
+ if (ps->is_shared_user == false) {
+ if (ps->thread_tot > 1) {
+ ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
+ BLI_spin_init(ps->tile_lock);
+ }
- image_undo_init_locks();
+ image_undo_init_locks();
+ }
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
@@ -3337,16 +3425,22 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
normal_short_to_float_v3(no, mv->no);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
if (ps->is_ortho) {
- if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
else {
sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
normalize_v3(viewDirPersp);
- if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
+ if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
@@ -3628,7 +3722,7 @@ static bool project_paint_backface_cull(
}
}
else {
- if (line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) {
+ if ((line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) != ps->is_flip_object) {
return true;
}
@@ -3670,10 +3764,11 @@ static void project_paint_prepare_all_faces(
ProjPaintState *ps, MemArena *arena,
const ProjPaintFaceLookup *face_lookup,
ProjPaintLayerClone *layer_clone,
- MTFace *tf_base)
+ MTFace *tf_base,
+ const bool is_multi_view)
{
/* Image Vars - keep track of images we have used */
- LinkNode *image_LinkList = NULL;
+ LinkNodePair image_LinkList = {NULL, NULL};
Image *tpage_last = NULL, *tpage;
TexPaintSlot *slot_last = NULL;
@@ -3729,25 +3824,26 @@ static void project_paint_prepare_all_faces(
ProjPaintFaceCoSS coSS;
proj_paint_face_coSS_init(ps, mf, &coSS);
- if (project_paint_flt_max_cull(ps, &coSS)) {
- continue;
- }
+ if (is_multi_view == false) {
+ if (project_paint_flt_max_cull(ps, &coSS)) {
+ continue;
+ }
#ifdef PROJ_DEBUG_WINCLIP
- if (project_paint_winclip(ps, mf, &coSS)) {
- continue;
- }
+ if (project_paint_winclip(ps, mf, &coSS)) {
+ continue;
+ }
#endif //PROJ_DEBUG_WINCLIP
-
- if (project_paint_backface_cull(ps, mf, &coSS)) {
- continue;
+ if (project_paint_backface_cull(ps, mf, &coSS)) {
+ continue;
+ }
}
if (tpage_last != tpage) {
- image_index = BLI_linklist_index(image_LinkList, tpage);
+ image_index = BLI_linklist_index(image_LinkList.list, tpage);
if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
BLI_linklist_append(&image_LinkList, tpage);
@@ -3767,18 +3863,22 @@ static void project_paint_prepare_all_faces(
}
/* build an array of images we use*/
- project_paint_build_proj_ima(ps, arena, image_LinkList);
+ if (ps->is_shared_user == false) {
+ project_paint_build_proj_ima(ps, arena, image_LinkList.list);
+ }
/* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList, NULL);
+ BLI_linklist_free(image_LinkList.list, NULL);
}
/* run once per stroke before projection painting */
-static void project_paint_begin(ProjPaintState *ps)
+static void project_paint_begin(
+ ProjPaintState *ps,
+ const bool is_multi_view, const char symmetry_flag)
{
ProjPaintLayerClone layer_clone;
ProjPaintFaceLookup face_lookup;
- MTFace *tf_base;
+ MTFace *tf_base = NULL;
MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
@@ -3792,10 +3892,13 @@ static void project_paint_begin(ProjPaintState *ps)
ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+ ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
/* paint onto the derived mesh */
- if (!proj_paint_state_dm_init(ps)) {
- return;
+ if (ps->is_shared_user == false) {
+ if (!proj_paint_state_dm_init(ps)) {
+ return;
+ }
}
proj_paint_face_lookup_init(ps, &face_lookup);
@@ -3817,11 +3920,13 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
- proj_paint_state_non_cddm_init(ps);
+ if (ps->is_shared_user == false) {
+ proj_paint_state_non_cddm_init(ps);
- proj_paint_state_cavity_init(ps);
+ proj_paint_state_cavity_init(ps);
+ }
- proj_paint_state_viewport_init(ps);
+ proj_paint_state_viewport_init(ps, symmetry_flag);
/* calculate vert screen coords
* run this early so we can calculate the x/y resolution of our bucket rect */
@@ -3850,7 +3955,9 @@ static void project_paint_begin(ProjPaintState *ps)
ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
#ifndef PROJ_DEBUG_NOSEAMBLEED
- proj_paint_state_seam_bleed_init(ps);
+ if (ps->is_shared_user == false) {
+ proj_paint_state_seam_bleed_init(ps);
+ }
#endif
proj_paint_state_thread_init(ps, reset_threads);
@@ -3858,7 +3965,7 @@ static void project_paint_begin(ProjPaintState *ps)
proj_paint_state_vert_flags_init(ps);
- project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base);
+ project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base, is_multi_view);
}
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
@@ -3867,7 +3974,7 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
if (ps->tool == PAINT_TOOL_CLONE) {
float projCo[4];
copy_v3_v3(projCo, ED_view3d_cursor3d_get(ps->scene, ps->v3d));
- mul_m4_v3(ps->ob->imat, projCo);
+ mul_m4_v3(ps->obmat_imat, projCo);
projCo[3] = 1.0f;
mul_m4_v4(ps->projectMat, projCo);
@@ -3879,14 +3986,16 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
static void project_paint_end(ProjPaintState *ps)
{
int a;
- ProjPaintImage *projIma;
image_undo_remove_masks();
/* dereference used image buffers */
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- DAG_id_tag_update(&projIma->ima->id, 0);
+ if (ps->is_shared_user == false) {
+ ProjPaintImage *projIma;
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
+ DAG_id_tag_update(&projIma->ima->id, 0);
+ }
}
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
@@ -3895,68 +4004,81 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->bucketRect);
MEM_freeN(ps->bucketFaces);
MEM_freeN(ps->bucketFlags);
- MEM_freeN(ps->dm_mtface);
- if (ps->do_layer_clone)
- MEM_freeN(ps->dm_mtface_clone);
- if (ps->thread_tot > 1) {
- BLI_spin_end(ps->tile_lock);
- MEM_freeN((void *)ps->tile_lock);
- }
- image_undo_end_locks();
+
+ if (ps->is_shared_user == false) {
+
+ /* must be set for non-shared */
+ BLI_assert(ps->dm_mtface || ps->is_shared_user);
+ if (ps->dm_mtface)
+ MEM_freeN(ps->dm_mtface);
+
+ if (ps->do_layer_clone)
+ MEM_freeN(ps->dm_mtface_clone);
+ if (ps->thread_tot > 1) {
+ BLI_spin_end(ps->tile_lock);
+ MEM_freeN((void *)ps->tile_lock);
+ }
+
+ image_undo_end_locks();
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- MEM_freeN(ps->vertFaces);
- MEM_freeN(ps->faceSeamFlags);
- MEM_freeN(ps->faceWindingFlags);
- MEM_freeN(ps->faceSeamUVs);
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ MEM_freeN(ps->vertFaces);
+ MEM_freeN(ps->faceSeamFlags);
+ MEM_freeN(ps->faceWindingFlags);
+ MEM_freeN(ps->faceSeamUVs);
+ }
+#endif
+
+ if (ps->do_mask_cavity) {
+ MEM_freeN(ps->cavities);
+ }
+
+ /* copy for subsurf/multires, so throw away */
+ if (ps->dm->type != DM_TYPE_CDDM) {
+ if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
+ if (ps->dm_mface) MEM_freeN(ps->dm_mface);
+ /* looks like these don't need copying */
+#if 0
+ if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
+ if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
+ if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
#endif
+ }
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+ }
if (ps->blurkernel) {
paint_delete_blur_kernel(ps->blurkernel);
MEM_freeN(ps->blurkernel);
}
- if (ps->do_mask_cavity) {
- MEM_freeN(ps->cavities);
- }
-
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
for (a = 0; a < ps->thread_tot; a++) {
BLI_memarena_free(ps->arena_mt[a]);
}
+}
- /* copy for subsurf/multires, so throw away */
- if (ps->dm->type != DM_TYPE_CDDM) {
- if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
- if (ps->dm_mface) MEM_freeN(ps->dm_mface);
- /* looks like these don't need copying */
-#if 0
- if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
- if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
- if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
-#endif
- }
+/* 1 = an undo, -1 is a redo. */
+static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
+{
+ pr->x1 = 10000000;
+ pr->y1 = 10000000;
- if (ps->dm_release)
- ps->dm->release(ps->dm);
+ pr->x2 = -1;
+ pr->y2 = -1;
+
+ pr->enabled = 1;
}
-/* 1 = an undo, -1 is a redo. */
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
{
int tot = PROJ_BOUNDBOX_SQUARED;
while (tot--) {
- pr->x1 = 10000000;
- pr->y1 = 10000000;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
-
+ partial_redraw_single_init(pr);
pr++;
}
}
@@ -4000,6 +4122,8 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
redraw = 1;
}
+
+ partial_redraw_single_init(pr);
}
projIma->touch = 0; /* clear for reuse */
@@ -4207,7 +4331,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = projPixel->pixel.f_pt[3];
projPixel->pixel.f_pt[3] = rgba[3] = mask;
@@ -4268,7 +4392,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
sub_v3_v3v3(rgba, rgba_pixel, rgba);
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = rgba_pixel[3];
rgba[3] = rgba_pixel[3] = mask;
@@ -4414,7 +4538,8 @@ static void *do_projectpaint_thread(void *ph_v)
const float brush_radius = ps->brush_size;
const float brush_radius_sq = brush_radius * brush_radius; /* avoid a square root with every dist comparison */
- short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
+ const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
+ 0 : (brush->flag & BRUSH_LOCK_ALPHA) != 0;
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_f = NULL;
@@ -4440,8 +4565,13 @@ static void *do_projectpaint_thread(void *ph_v)
/* Check this bucket and its faces are initialized */
if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ rctf clip_rect = bucket_bounds;
+ clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
/* No pixels initialized */
- project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
+ project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
}
if (ps->source != PROJ_SRC_VIEW) {
@@ -4531,8 +4661,17 @@ static void *do_projectpaint_thread(void *ph_v)
}
if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
}
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
@@ -4583,7 +4722,7 @@ static void *do_projectpaint_thread(void *ph_v)
if (dist_sq <= brush_radius_sq) {
dist = sqrtf(dist_sq);
- falloff = BKE_brush_curve_strength(ps->brush, dist, brush_radius);
+ falloff = BKE_brush_curve_strength_clamped(ps->brush, dist, brush_radius);
if (falloff > 0.0f) {
float texrgb[3];
@@ -4697,11 +4836,20 @@ static void *do_projectpaint_thread(void *ph_v)
else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
break;
}
- }
- if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (lock_alpha) {
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
+ }
}
/* done painting */
@@ -4818,7 +4966,8 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
/* calculate pivot for rotation around seletion if needed */
if (U.uiflag & USER_ORBIT_SELECTION) {
float w[3];
- int side, index;
+ int index;
+ int side;
index = project_paint_PickFace(ps, pos, w, &side);
@@ -4837,7 +4986,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
ups->average_stroke_counter++;
- mul_m4_v3(ps->ob->obmat, world);
+ mul_m4_v3(ps->obmat, world);
add_v3_v3(ups->average_stroke_accum, world);
ups->last_stroke_valid = true;
}
@@ -4847,33 +4996,21 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
-void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size)
+static void paint_proj_stroke_ps(
+ const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size,
+ /* extra view */
+ ProjPaintState *ps
+ )
{
- ProjPaintState *ps = pps;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
Brush *brush = ps->brush;
Scene *scene = ps->scene;
- int a;
ps->brush_size = size;
ps->blend = brush->blend;
if (eraser)
ps->blend = IMB_BLEND_ERASE_ALPHA;
-
- /* clone gets special treatment here to avoid going through image initialization */
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- View3D *v3d = ps->v3d;
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
- int mval_i[2] = {(int)pos[0], (int)pos[1]};
-
- view3d_operator_needs_opengl(C);
-
- if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false, NULL))
- return;
-
- ED_region_tag_redraw(ps->ar);
-
- return;
- }
/* handle gradient and inverted stroke color here */
if (ps->tool == PAINT_TOOL_DRAW) {
@@ -4894,14 +5031,42 @@ void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], co
}
}
- /* continue adding to existing partial redraw rects until redraw */
- if (!ps->need_redraw) {
- for (a = 0; a < ps->image_tot; a++)
- partial_redraw_array_init(ps->projImages[a].partRedrawRect);
+ if (project_paint_op(ps, prev_pos, pos)) {
+ ps_handle->need_redraw = true;
+ project_image_refresh_tagged(ps);
}
+}
+
+
+void paint_proj_stroke(
+ const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size)
+{
+ int i;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+
+ /* clone gets special treatment here to avoid going through image initialization */
+ if (ps_handle->is_clone_cursor_pick) {
+ Scene *scene = ps_handle->scene;
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ int mval_i[2] = {(int)pos[0], (int)pos[1]};
- if (project_paint_op(ps, prev_pos, pos))
- ps->need_redraw = true;
+ view3d_operator_needs_opengl(C);
+
+ if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
+ return;
+
+ ED_region_tag_redraw(ar);
+
+ return;
+ }
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
+ }
}
@@ -4920,7 +5085,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->blend = brush->blend;
/* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */
if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ?
+ ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
ps->blurkernel = paint_new_blur_kernel(brush, true);
@@ -5001,6 +5166,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->normal_angle_range <= 0.0f)
ps->do_mask_normal = false; /* no need to do blending */
+ ps->normal_angle__cos = cosf(ps->normal_angle);
+ ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
+
ps->dither = settings->imapaint.dither;
return;
@@ -5008,51 +5176,116 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
{
- ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ProjStrokeHandle *ps_handle;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int i;
+ bool is_multi_view;
+ char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
- project_state_init(C, ob, ps, mode);
+ ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
+ ps_handle->scene = scene;
+ ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
- if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
+ /* bypass regular stroke logic */
+ if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) &&
+ (mode == BRUSH_STROKE_INVERT))
+ {
view3d_operator_needs_opengl(C);
- return ps;
+ ps_handle->is_clone_cursor_pick = true;
+ return ps_handle;
}
- paint_brush_init_tex(ps->brush);
+ ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
- ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
+ is_multi_view = (ps_handle->ps_views_tot != 1);
- if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ps_handle->ps_views[i] = ps;
+ }
+
+ if (ps_handle->symmetry_flags) {
+ int index = 0;
+
+ int x = 0;
+ do {
+ int y = 0;
+ do {
+ int z = 0;
+ do {
+ symmetry_flag_views[index++] = (
+ (x ? PAINT_SYMM_X : 0) |
+ (y ? PAINT_SYMM_Y : 0) |
+ (z ? PAINT_SYMM_Z : 0));
+ BLI_assert(index <= ps_handle->ps_views_tot);
+ } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
+ } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
+ } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
+ BLI_assert(index == ps_handle->ps_views_tot);
}
- ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush);
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ project_state_init(C, ob, ps, mode);
+
+ if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
+ ps_handle->ps_views_tot = i + 1;
+ goto fail;
+ }
+ }
/* Don't allow brush size below 2 */
- if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
- BKE_brush_size_set(ps->scene, ps->brush, 2 * U.pixelsize);
+ if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
+ BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
/* allocate and initialize spatial data structures */
- project_paint_begin(ps);
- if (ps->dm == NULL) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ project_image_refresh_tagged(ps);
+
+ /* re-use! */
+ if (i != 0) {
+ ps->is_shared_user = true;
+ PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
+ }
+
+ project_paint_begin(ps, is_multi_view, symmetry_flag_views[i]);
+
+ paint_proj_begin_clone(ps, mouse);
+
+ if (ps->dm == NULL) {
+ goto fail;
+ return NULL;
+ }
}
- paint_proj_begin_clone(ps, mouse);
+ paint_brush_init_tex(ps_handle->brush);
+
+ return ps_handle;
+
- return ps;
+fail:
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ MEM_freeN(ps);
+ }
+ MEM_freeN(ps_handle);
+ return NULL;
}
-void paint_proj_redraw(const bContext *C, void *pps, bool final)
+void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
{
- ProjPaintState *ps = pps;
-
- if (ps->need_redraw) {
- project_image_refresh_tagged(ps);
+ ProjStrokeHandle *ps_handle = ps_handle_p;
- ps->need_redraw = false;
+ if (ps_handle->need_redraw) {
+ ps_handle->need_redraw = false;
}
else if (!final) {
return;
@@ -5067,19 +5300,34 @@ void paint_proj_redraw(const bContext *C, void *pps, bool final)
}
}
-void paint_proj_stroke_done(void *pps)
+void paint_proj_stroke_done(void *ps_handle_p)
{
- ProjPaintState *ps = pps;
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- MEM_freeN(ps);
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+ Scene *scene = ps_handle->scene;
+ int i;
+
+ if (ps_handle->is_clone_cursor_pick) {
+ MEM_freeN(ps_handle);
return;
}
- BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size);
- paint_brush_exit_tex(ps->brush);
+ for (i = 1; i < ps_handle->ps_views_tot; i++) {
+ PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
+ }
+
+ BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
+
+ paint_brush_exit_tex(ps_handle->brush);
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps;
+ ps = ps_handle->ps_views[i];
+ project_paint_end(ps);
+ MEM_freeN(ps);
+
+ }
- project_paint_end(ps);
- MEM_freeN(ps);
+ MEM_freeN(ps_handle);
}
/* use project paint to re-apply an image */
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
@@ -5159,7 +5407,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ED_image_undo_restore, ED_image_undo_free, NULL);
/* allocate and initialize spatial data structures */
- project_paint_begin(&ps);
+ project_paint_begin(&ps, false, 0);
if (ps.dm == NULL) {
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
@@ -5233,7 +5481,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (w > maxsize) w = maxsize;
if (h > maxsize) h = maxsize;
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@@ -5241,7 +5489,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- image = BKE_image_add_from_imbuf(ibuf);
+ image = BKE_image_add_from_imbuf(ibuf, "image_view");
/* Drop reference to ibuf so that the image owns it */
IMB_freeImBuf(ibuf);
@@ -5271,8 +5519,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
array[2] = is_ortho ? 1.0f : 0.0f;
IDP_AddToGroup(idgroup, view_data);
-
- rename_id(&image->id, "image_view");
}
return OPERATOR_FINISHED;
@@ -5444,7 +5690,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
RNA_string_get(op->ptr, "name", imagename);
}
ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
- gen_type, color);
+ gen_type, color, false);
return ima;
}
@@ -5487,7 +5733,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
}
else {
- MTex *mtex = add_mtex_id(&ma->id, -1);
+ MTex *mtex = BKE_texture_mtex_add_id(&ma->id, -1);
/* successful creation of mtex layer, now create set */
if (mtex) {
@@ -5506,7 +5752,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- mtex->tex = add_texture(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->tex = BKE_texture_add(bmain, DATA_(layer_type_items[type_id].name));
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 9e558092f73..fd7e053fea3 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -34,14 +34,11 @@
struct ARegion;
struct bContext;
-struct bglMats;
struct Brush;
struct ImagePool;
struct ColorSpace;
struct ColorManagedDisplay;
struct ListBase;
-struct Material;
-struct Mesh;
struct MTex;
struct Object;
struct PaintStroke;
@@ -55,7 +52,6 @@ struct ViewContext;
struct wmEvent;
struct wmOperator;
struct wmOperatorType;
-struct ImagePaintState;
struct wmWindowManager;
struct DMCoNo;
enum PaintMode;
@@ -149,7 +145,7 @@ typedef struct ImagePaintPartialRedraw {
int image_texture_paint_poll(struct bContext *C);
void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev);
void image_undo_remove_masks(void);
void image_undo_init_locks(void);
void image_undo_end_locks(void);
@@ -164,7 +160,7 @@ void paint_2d_redraw(const 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);
-void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
+void paint_2d_gradient_fill(const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], const bool eraser, float pressure, float distance, float size);
void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 25f22996050..2254bc991b6 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -290,7 +290,7 @@ typedef struct LassoMaskData {
static bool is_effected_lasso(LassoMaskData *data, float co[3])
{
float scr_co_f[2];
- short scr_co_s[2];
+ int scr_co_s[2];
float co_final[3];
flip_v3_v3(co_final, co, data->symmpass);
@@ -301,8 +301,13 @@ static bool is_effected_lasso(LassoMaskData *data, float co[3])
scr_co_s[1] = scr_co_f[1];
/* clip against screen, because lasso is limited to screen only */
- if (scr_co_s[0] < data->rect.xmin || scr_co_s[1] < data->rect.ymin || scr_co_s[0] >= data->rect.xmax || scr_co_s[1] >= data->rect.ymax)
+ if ((scr_co_s[0] < data->rect.xmin) ||
+ (scr_co_s[1] < data->rect.ymin) ||
+ (scr_co_s[0] >= data->rect.xmax) ||
+ (scr_co_s[1] >= data->rect.ymax))
+ {
return false;
+ }
scr_co_s[0] -= data->rect.xmin;
scr_co_s[1] -= data->rect.ymin;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 121b0b83a4b..eebd49895ef 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -196,7 +196,10 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
Brush *brush = paint->brush;
PaintMode mode = BKE_paintmode_get_active_from_context(C);
Palette *palette = paint->palette;
- PaletteColor *color = BKE_palette_color_add(palette);
+ PaletteColor *color;
+
+ color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) {
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
@@ -231,7 +234,9 @@ static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
Palette *palette = paint->palette;
PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
- BKE_palette_color_remove(palette, color);
+ if (color) {
+ BKE_palette_color_remove(palette, color);
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index bfd429d0924..ece6ea7a940 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -68,7 +68,7 @@
#include <float.h>
#include <math.h>
-// #define DEBUG_TIME
+#define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"
@@ -347,7 +347,8 @@ static bool paint_brush_update(bContext *C,
if (!stroke->brush_init) {
copy_v2_v2(ups->last_rake, mouse_init);
}
- else {
+ /* curve strokes do their own rake calculation */
+ else if (!(brush->flag & BRUSH_CURVE)) {
paint_calculate_rake_rotation(ups, brush, mouse_init);
}
}
@@ -556,7 +557,7 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
g = 1.0f / m;
max = 0;
for (i = 0; i < m; i++) {
- float overlap = paint_stroke_overlapped_curve(br, i * g, spacing);
+ float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
if (overlap > max)
max = overlap;
@@ -671,9 +672,8 @@ PaintStroke *paint_stroke_new(bContext *C,
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
- if (stroke->stroke_mode == BRUSH_STROKE_INVERT)
- {
- if (br->flag & (BRUSH_CURVE | BRUSH_LINE)) {
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
+ if (br->flag & (BRUSH_CURVE)) {
RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
}
}
@@ -955,6 +955,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
Brush *br = stroke->brush;
if (br->flag & BRUSH_CURVE) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
@@ -975,18 +976,39 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
int j;
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
PaintCurvePoint *pcp_next = pcp + 1;
+ bool do_rake = false;
- for (j = 0; j < 2; j++)
+ for (j = 0; j < 2; j++) {
BKE_curve_forward_diff_bezier(
pcp->bez.vec[1][j],
pcp->bez.vec[2][j],
pcp_next->bez.vec[0][j],
pcp_next->bez.vec[1][j],
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ {
+ do_rake = true;
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_tangent_bezier(
+ pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ }
for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (do_rake) {
+ float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
+ paint_update_brush_rake_rotation(ups, br, rotation);
+ }
+
if (!stroke->stroke_started) {
stroke->last_pressure = 1.0;
copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
@@ -1015,14 +1037,14 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
return false;
}
-static void paint_stroke_line_constrain (PaintStroke *stroke, float mouse[2])
+static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
{
if (stroke->constrain_line) {
float line[2];
float angle, len, res;
sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
- angle = atan2(line[1], line[0]);
+ angle = atan2f(line[1], line[0]);
len = len_v2(line);
/* divide angle by PI/4 */
@@ -1129,7 +1151,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
else if (br->flag & BRUSH_LINE) {
- if (event->ctrl)
+ if (event->alt)
stroke->constrain_line = true;
else
stroke->constrain_line = false;
@@ -1137,8 +1159,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
- {
+ if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
}
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 0293a0bfc00..42f0aaab173 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -331,32 +331,33 @@ void ED_undo_paint_step_num(bContext *C, int type, int step)
undo_step_num(C, &MeshUndoStack, step);
}
-static char *undo_stack_get_name(UndoStack *stack, int nr, int *active)
+static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active)
{
UndoElem *uel;
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&stack->elems, nr);
if (uel) {
- if (active && uel == stack->current)
- *active = 1;
+ if (r_active && (uel == stack->current)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
}
-const char *ED_undo_paint_get_name(bContext *C, int type, int nr, int *active)
+const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active)
{
if (type == UNDO_PAINT_IMAGE) {
undo_stack_cleanup(&ImageUndoStack, C);
- return undo_stack_get_name(&ImageUndoStack, nr, active);
+ return undo_stack_get_name(&ImageUndoStack, nr, r_active);
}
else if (type == UNDO_PAINT_MESH) {
undo_stack_cleanup(&MeshUndoStack, C);
- return undo_stack_get_name(&MeshUndoStack, nr, active);
+ return undo_stack_get_name(&MeshUndoStack, nr, r_active);
}
return NULL;
}
@@ -379,7 +380,7 @@ bool ED_undo_paint_empty(int type)
return false;
}
-int ED_undo_paint_valid(int type, const char *name)
+bool ED_undo_paint_is_valid(int type, const char *name)
{
UndoStack *stack;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index c0ed5005397..4e550543479 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -379,7 +379,7 @@ static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *
return 0;
/* sample only on the exact position */
- *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+ *r_index = ED_view3d_backbuf_sample(vc, mval[0], mval[1]);
if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;
@@ -395,7 +395,7 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
{
Image *ima;
MPoly *mp = me->mpoly + face_index;
- Material *ma = give_current_material(ob, mp->mat_nr + 1);;
+ Material *ma = give_current_material(ob, mp->mat_nr + 1);
ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
return ima;
@@ -439,6 +439,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
}
@@ -486,12 +487,15 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (u < 0.0f) u += 1.0f;
if (v < 0.0f) v += 1.0f;
- u = u * ibuf->x - 0.5f;
- v = v * ibuf->y - 0.5f;
+ u = u * ibuf->x;
+ v = v * ibuf->y;
if (ibuf->rect_float) {
float rgba_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
straight_to_premul_v4(rgba_f);
if (use_palette) {
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
@@ -503,7 +507,10 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
else {
unsigned char rgba[4];
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index e87dd6c2810..5af327e7b49 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -37,6 +37,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
@@ -208,7 +209,7 @@ static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
{
/* if no mcol: do not do */
/* if tface: only the involved faces, otherwise all */
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
MFace *mface;
int a;
short *scolmain, *scol;
@@ -279,7 +280,7 @@ static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
static void do_shared_vertexcol(Mesh *me, bool *mlooptag, bool *mfacetag, const bool do_tessface)
{
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
MPoly *mp;
int (*scol)[4];
int i, j;
@@ -768,7 +769,7 @@ BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int f
/* See if are lighter, if so mix, else don't do anything.
* if the paint col is darker then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) > rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -801,7 +802,7 @@ BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fa
/* See if were darker, if so mix, else don't do anything.
* if the paint col is brighter then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) < rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -877,7 +878,7 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
* brushes with size > 64, why is this here? */
/*if (size > 64.0) size = 64.0;*/
- ibuf = view3d_read_backbuf(vc, x - size, y - size, x + size, y + size);
+ ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size);
if (ibuf) {
unsigned int *rt = ibuf->rect;
@@ -935,7 +936,7 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co
else {
factor = 1.0f;
}
- return factor * BKE_brush_curve_strength(brush, dist, brush_size_pressure);
+ return factor * BKE_brush_curve_strength_clamped(brush, dist, brush_size_pressure);
}
}
if (rgba)
@@ -1090,7 +1091,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d) {
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
unsigned int index;
@@ -1176,7 +1177,7 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ 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;
@@ -3216,7 +3217,7 @@ static void gradientVert_update(DMGradient_userData *grad_data, int index)
/* no need to clamp 'alpha' yet */
/* adjust weight */
- alpha = BKE_brush_curve_strength(grad_data->brush, alpha, 1.0f);
+ alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
if (alpha != 0.0f) {
MDeformVert *dv = &me->dvert[index];
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index ae729248f7e..c939eb6df35 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -186,7 +186,7 @@ static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
/* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
if (LIKELY(dm->foreachMappedVert)) {
- fill_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
+ copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index ea046b7d4d5..ede90b6e1f1 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -116,6 +116,13 @@ static int system_physical_thread_count(void)
}
#endif /* __APPLE__ */
+/** \name Tool Capabilities
+ *
+ * Avoid duplicate checks, internal logic only,
+ * share logic with #rna_def_sculpt_capabilities where possible.
+ *
+ * \{ */
+
/* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
{
@@ -133,6 +140,43 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
return 0;
}
+static bool sculpt_tool_needs_original(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+}
+
+static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_LAYER);
+}
+
+/**
+ * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
+ */
+static int sculpt_brush_needs_normal(const Brush *brush)
+{
+ return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
+ (brush->normal_weight > 0)) ||
+
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
+
+ (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
+}
+
+/** \} */
typedef enum StrokeFlags {
@@ -182,8 +226,6 @@ typedef struct StrokeCache {
ViewContext *vc;
Brush *brush;
- float (*face_norms)[3]; /* Copy of the mesh faces' normals */
-
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -285,30 +327,70 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->coords) {
- orig_data->co = orig_data->coords[iter->i];
+ if (orig_data->bm_log) {
+ BM_log_original_vert_data(
+ orig_data->bm_log, iter->bm_vert,
+ &orig_data->co, &orig_data->no);
}
else {
- orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
- }
-
- if (orig_data->normals) {
+ orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
- else {
- orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert);
- }
}
else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
- if (orig_data->vmasks) {
- orig_data->mask = orig_data->vmasks[iter->i];
+ if (orig_data->bm_log) {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
}
else {
- orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ orig_data->mask = orig_data->vmasks[iter->i];
}
}
}
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ *
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+/**
+ * \param plane Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(
+ SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(
+ const SculptProjectVector *spvc, const float vec[3],
+ float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+/** \} */
+
+
/**********************************************************************/
/* Returns true if the stroke will use dynamic topology, false
@@ -317,8 +399,8 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
- const Brush *brush)
+static bool sculpt_stroke_is_dynamic_topology(
+ const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -328,20 +410,8 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
* dynamic-topology */
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
-
- (!ELEM(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
-
- /* These brushes could handle dynamic topology,
- * but user feedback indicates it's better not
- * to */
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_MASK)));
+
+ SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
@@ -349,17 +419,11 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
const Brush *brush = BKE_paint_brush(&sd->paint);
- int i;
PBVHNode **nodes;
int n, totnode;
-#ifndef _OPENMP
- (void)sd; /* quied unused warning */
-#endif
-
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
/* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
@@ -404,12 +468,6 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
}
}
- if (ss->face_normals) {
- for (i = 0; i < ss->totpoly; i++) {
- copy_v3_v3(ss->face_normals[i], cache->face_norms[i]);
- }
- }
-
if (nodes)
MEM_freeN(nodes);
}
@@ -509,7 +567,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
}
}
-BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
RegionView3D *rv3d = test->clip_rv3d;
return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
@@ -547,7 +605,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
+static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
{
if (sculpt_brush_test_clipping(test, co)) {
return 0;
@@ -555,7 +613,7 @@ static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static bool sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
float side = M_SQRT1_2;
float local_co[3];
@@ -608,7 +666,7 @@ static float frontface(Brush *br, const float sculpt_normal[3],
#if 0
-static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[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)) {
float t1[3], t2[3], t3[3], dist;
@@ -616,7 +674,7 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
- cross_v3_v3v3(t3, an, t1);
+ cross_v3_v3v3(t3, area_no, t1);
dist = len_v3(t3) / len_v3(t2);
@@ -702,18 +760,447 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
}
}
+/** \name Calculate Normal and Center
+ *
+ * Calculate geometry surrounding the brush center.
+ * (optionally using original coordinates).
+ *
+ * Functions are:
+ * - #calc_area_center
+ * - #calc_area_normal
+ * - #calc_area_normal_and_center
+ *
+ * \note These are all _very_ similar, when changing one, check others.
+ * \{ */
+
+static void calc_area_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ 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_co[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ 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) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ cross_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+}
+
+
+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);
+ 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_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ 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) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 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(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ 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_co[2][3] = {{0.0f}};
+ float area_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ 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) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
+static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
const float root_alpha = BKE_brush_alpha_get(scene, brush);
float alpha = root_alpha * root_alpha;
- float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
@@ -927,132 +1414,34 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
-static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
-{
- if ((dot_v3v3(view_vec, fno)) > 0) {
- add_v3_v3(out, fno);
- }
- else {
- add_v3_v3(out_flip, fno); /* out_flip is used when out is {0,0,0} */
- }
-}
-
-static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
-{
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
- int n;
- bool original;
-
- /* Grab brush requires to test on original data (see r33888 and
- * bug #25371) */
- original = (BKE_paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
- true : ss->cache->original);
-
- /* In general the original coords are not available with dynamic
- * topology
- *
- * Mask tool could not use undo nodes to get coordinates from
- * since the coordinates are not stored in those odes.
- * And mask tool is not gonna to modify vertex coordinates,
- * so we don't actually need to use modified coords.
- */
- if (ss->bm || brush->sculpt_tool == SCULPT_TOOL_MASK)
- original = false;
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(an);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (original) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- else {
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
- }
- }
-
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-}
-
/* Calculate primary direction of movement for many brushes */
-static void calc_sculpt_normal(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3])
+static void calc_sculpt_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
const SculptSession *ss = ob->sculpt;
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, r_area_no);
break;
default:
@@ -1153,27 +1542,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* Test whether the StrokeCache.sculpt_normal needs update in
- * do_brush_action() */
-static int brush_needs_sculpt_normal(const Brush *brush)
-{
- return ((ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_SNAKE_HOOK) &&
- (brush->normal_weight > 0)) ||
-
- ELEM(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
-
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
-}
-
/* For the smooth brush, uses the neighboring vertices around vert to calculate
* a smoothed location for vert. Skips corner vertices (used by only one
* polygon.) */
@@ -1183,20 +1551,19 @@ static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
const MVert *mvert = ss->mvert;
float (*deform_co)[3] = ss->deform_cos;
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vert_map->count > 1) {
int i, total = 0;
+ zero_v3(avg);
+
for (i = 0; i < vert_map->count; i++) {
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] :
mvert[f_adj_v[j]].co);
@@ -1227,12 +1594,11 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
for (i = 0; i < ss->pmap[vert].count; i++) {
const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
avg += vmask[f_adj_v[j]];
total++;
}
@@ -1248,22 +1614,24 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
/* Same logic as neighbor_average(), but for bmesh rather than mesh */
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
- const int vfcount = BM_vert_face_count(v);
+ /* logic for 3 or more is identical */
+ const int vfcount = BM_vert_face_count_ex(v, 3);
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vfcount > 1) {
BMIter liter;
BMLoop *l;
int i, total = 0;
+ zero_v3(avg);
+
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
- add_v3_v3(avg, adj_v[i]->co);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
total++;
}
}
@@ -1279,7 +1647,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
-static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
{
BMIter liter;
BMLoop *l;
@@ -1287,13 +1655,12 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
int i, total = 0;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ /* skip this vertex */
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- BMVert *v2 = adj_v[i];
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v2->head.data,
- CD_PAINT_MASK);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
avg += (*vmask);
total++;
}
@@ -1303,9 +1670,7 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
return avg / (float)total;
}
else {
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v->head.data,
- CD_PAINT_MASK);
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
return (*vmask);
}
}
@@ -1368,7 +1733,7 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.no, vd.fno,
smooth_mask ? 0 : *vd.mask);
if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask;
+ float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0, 1);
@@ -1399,12 +1764,11 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
SculptBrushTest test;
CCGElem **griddata, *data;
CCGKey key;
- DMGridAdjacency *gridadj, *adj;
float (*tmpgrid_co)[3], (*tmprow_co)[3];
float *tmpgrid_mask, *tmprow_mask;
int v1, v2, v3, v4;
int thread_num;
- BLI_bitmap **grid_hidden;
+ BLI_bitmap * const *grid_hidden;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
@@ -1412,7 +1776,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata, &gridadj);
+ NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -1429,9 +1793,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
for (i = 0; i < totgrid; ++i) {
int gi = grid_indices[i];
- BLI_bitmap *gh = grid_hidden[gi];
+ const BLI_bitmap *gh = grid_hidden[gi];
data = griddata[gi];
- adj = &gridadj[gi];
if (smooth_mask)
memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
@@ -1497,18 +1860,6 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
continue;
}
- if (x == 0 && adj->index[0] == -1)
- continue;
-
- if (x == gridsize - 1 && adj->index[2] == -1)
- continue;
-
- if (y == 0 && adj->index[3] == -1)
- continue;
-
- if (y == gridsize - 1 && adj->index[1] == -1)
- continue;
-
index = x + y * gridsize;
co = CCG_elem_offset_co(&key, data, index);
fno = CCG_elem_offset_no(&key, data, index);
@@ -1699,6 +2050,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float brush_alpha;
int n;
+ SculptProjectVector spvc;
+
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
@@ -1715,6 +2068,10 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
+ * Without this we get a 'flat' surface surrounding the pinch */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
/* threaded loop over nodes */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -1739,6 +2096,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
sub_v3_v3v3(val1, test.location, vd.co);
mul_v3_fl(val1, fade * flippedbstrength);
+ sculpt_project_v3(&spvc, val1, val1);
+
/* then we draw */
mul_v3_v3fl(val2, offset, fade);
@@ -2132,233 +2491,10 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
-static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- int count = 0;
- int count_flip = 0;
-
- float fc_flip[3] = {0.0, 0.0, 0.0};
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flip += private_count_flip;
- }
- }
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flip != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flip);
- else
- zero_v3(fc);
-}
-
-/* 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_flatten_center(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3], float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- /* for area normal */
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
- float fc_flip[3] = {0.0f, 0.0f, 0.0f};
-
- /* for flatten center */
- int count = 0;
- int count_flipped = 0;
-
- (void)sd; /* unused w/o openmp */
-
- /* for area normal */
- zero_v3(an);
-
- /* for flatten center */
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- /* for area normal */
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_an, vd.fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, vd.fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
-
- /* for flatten center */
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flipped += private_count_flip;
- }
- }
-
- /* for area normal */
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-
- /* for flatten center */
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flipped != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flipped);
- else
- zero_v3(fc);
-}
-
-static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2369,29 +2505,23 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
+ calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
break;
default:
@@ -2401,50 +2531,54 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
/* for flatten center */
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_flatten_center(sd, ob, nodes, totnode, fc);
+ calc_area_center(sd, ob, nodes, totnode, r_area_co);
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, an);
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, fc);
+ copy_v3_v3(ss->cache->last_center, r_area_co);
}
else {
/* for area normal */
- copy_v3_v3(an, ss->cache->sculpt_normal);
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
/* for flatten center */
- copy_v3_v3(fc, ss->cache->last_center);
+ copy_v3_v3(r_area_co, ss->cache->last_center);
/* for area normal */
- flip_v3(an, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
/* for flatten center */
- flip_v3(fc, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
/* for area normal */
- mul_m4_v3(ss->cache->symm_rot_mat, an);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
/* for flatten center */
- mul_m4_v3(ss->cache->symm_rot_mat, fc);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
}
}
/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+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(StrokeCache *cache, Brush *brush, float val[3])
+static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
+static bool plane_point_side_flip(
+ const float co[3], const float plane_normal[3], const float plane_center[3],
+ const bool flip)
{
float delta[3];
float d;
@@ -2457,7 +2591,7 @@ static int plane_point_side_flip(float co[3], float plane_normal[3], float plane
return d <= 0.0f;
}
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
+static int plane_point_side(const float co[3], const float plane_normal[3], const float plane_center[3])
{
float delta[3];
@@ -2486,8 +2620,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
@@ -2497,13 +2631,13 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2521,7 +2655,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2551,16 +2685,16 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
int n;
float temp[3];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
flip = bstrength < 0;
@@ -2571,11 +2705,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
- /* add_v3_v3v3(p, ss->cache->location, an); */
+ /* add_v3_v3v3(p, ss->cache->location, area_no); */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2590,15 +2724,17 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, an, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* 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);
@@ -2625,9 +2761,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float displace;
- float sn[3];
- float an[3];
- float fc[3];
+ float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
+ float area_no[3]; /* geometry normal */
+ float area_co[3];
int n;
@@ -2636,14 +2772,14 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float scale[4][4];
float tmat[4][4];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
else
- copy_v3_v3(an, sn);
+ copy_v3_v3(area_no, area_no_sp);
/* delay the first daub because grab delta is not setup */
if (ss->cache->first_time)
@@ -2658,16 +2794,16 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, sn, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
/* init mat */
- cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry);
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
mat[0][3] = 0;
- cross_v3_v3v3(mat[1], an, mat[0]);
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
mat[1][3] = 0;
- copy_v3_v3(mat[2], an);
+ copy_v3_v3(mat[2], area_no);
mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location);
mat[3][3] = 1;
@@ -2691,15 +2827,17 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, sn, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, sn, fc);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* 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);
@@ -2724,8 +2862,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2734,13 +2872,13 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2755,11 +2893,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, an, fc)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2788,8 +2926,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2798,13 +2936,13 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = -radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2819,11 +2957,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, an, fc)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2849,7 +2987,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3]/*, an[3]*/;
+ float offset[3]/*, area_no[3]*/;
int n;
float gravity_vector[3];
@@ -2946,11 +3084,7 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ 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);
@@ -2981,9 +3115,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
- ss->cache->location,
- ss->cache->radius);
+ BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, mode,
+ ss->cache->location,
+ (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL,
+ ss->cache->radius);
}
MEM_freeN(nodes);
@@ -3005,11 +3141,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ 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);
/* Only act if some verts are inside the brush area */
@@ -3024,7 +3156,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_node_mark_update(nodes[n]);
}
- if (brush_needs_sculpt_normal(brush))
+ if (sculpt_brush_needs_normal(brush))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3144,8 +3276,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
/* first line is tools that don't support proxies */
- if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER) ||
- ss->cache->supports_gravity)
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
{
/* these brushes start from original coordinates */
const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
@@ -3223,7 +3355,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
+ if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -3484,8 +3616,6 @@ static const char *sculpt_tool_name(Sculpt *sd)
static void sculpt_cache_free(StrokeCache *cache)
{
- if (cache->face_norms)
- MEM_freeN(cache->face_norms);
if (cache->dial)
MEM_freeN(cache->dial);
MEM_freeN(cache);
@@ -3557,7 +3687,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL, NULL);
+ &gridsize, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3745,21 +3875,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- if (ss->face_normals) {
- cache->face_norms = MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms");
- for (i = 0; i < ss->totpoly; ++i) {
- copy_v3_v3(cache->face_norms[i], ss->face_normals[i]);
- }
- }
-
cache->original = 1;
}
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
- SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
- {
+ if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
}
@@ -4251,6 +4370,9 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
+ }
else {
BKE_pbvh_bmesh_detail_size_set(
ss->pbvh,
@@ -4259,7 +4381,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -4746,7 +4868,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
@@ -4838,6 +4960,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sd->symmetrize_direction, 0.00001f);
sculpt_dynamic_topology_triangulate(ss->bm);
+ /* bisect operator flags edges (keep tags clean for edge queue) */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end();
@@ -4912,7 +5037,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Leave sculptmode */
ob->mode &= ~mode_flag;
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
}
@@ -4941,16 +5066,16 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
- if (!ts->sculpt->detail_size) {
+ if (!ts->sculpt->detail_size)
ts->sculpt->detail_size = 12;
- }
-
+ if (!ts->sculpt->detail_percent)
+ ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
ts->sculpt->constant_detail = 30.0f;
/* Create sculpt mode session data */
if (ob->sculpt)
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
sculpt_init_session(scene, ob);
@@ -5033,7 +5158,10 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
- while (BKE_pbvh_bmesh_update_topology(ss->pbvh, PBVH_Collapse | PBVH_Subdivide, bb_min, size)) {
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
+ bb_min, NULL, size))
+ {
for (i = 0; i < totnodes; i++)
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
@@ -5177,6 +5305,10 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
else {
set_brush_rc_props(&props_ptr, "sculpt", "detail_size", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a61f571fdf6..8f1a4655c37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -41,14 +41,8 @@
#include "BKE_pbvh.h"
struct bContext;
-struct Brush;
struct KeyBlock;
-struct Mesh;
-struct MultiresModifierData;
struct Object;
-struct Scene;
-struct Sculpt;
-struct SculptStroke;
struct SculptUndoNode;
int sculpt_mode_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index a4adbc6bca8..2f0957c3b60 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -484,7 +484,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
BKE_mesh_calc_normals_tessface(mesh->mvert, mesh->totvert,
mesh->mface, mesh->totface, NULL);
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
tag_update |= true;
}
@@ -581,7 +581,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid,
"unode->grid_hidden");
@@ -610,7 +610,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
if (node) {
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL, NULL);
+ &maxgrid, &gridsize, NULL);
unode->totvert = totvert;
}
@@ -842,7 +842,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
if (unode->grids) {
int totgrid, *grids;
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
memcpy(unode->grids, grids, sizeof(int) * totgrid);
}
else {
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index a9feb9f48de..e01d8a6bd17 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -315,7 +315,7 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata,
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * (tmp_uvdata[i].p[0] - 0.5f * (tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter));
sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * (tmp_uvdata[i].p[1] - 0.5f * (tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
@@ -379,7 +379,7 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *scul
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] + strength * tmp_uvdata[i].p[0];
sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] + strength * tmp_uvdata[i].p[1];
@@ -454,7 +454,7 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *e
if ((dist = dot_v2v2(diff, diff)) <= radius) {
UvElement *element;
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
normalize_v2(diff);
sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
@@ -612,18 +612,18 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
/* We will need island information */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, true);
+ data->elementMap = BM_uv_element_map_create(bm, false, true, true);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, true);
+ data->elementMap = BM_uv_element_map_create(bm, true, true, true);
}
}
else {
if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, false, false);
+ data->elementMap = BM_uv_element_map_create(bm, false, true, false);
}
else {
- data->elementMap = BM_uv_element_map_create(bm, true, false);
+ data->elementMap = BM_uv_element_map_create(bm, true, true, false);
}
}
@@ -822,7 +822,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
diff[1] /= aspectRatio;
if ((dist = dot_v2v2(diff, diff)) <= radius) {
float strength;
- strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
data->initial_stroke->initialSelection[counter].uv = i;
data->initial_stroke->initialSelection[counter].strength = strength;
diff --git a/source/blender/editors/sound/sound_intern.h b/source/blender/editors/sound/sound_intern.h
index e8a8ec55ab5..ace173abdee 100644
--- a/source/blender/editors/sound/sound_intern.h
+++ b/source/blender/editors/sound/sound_intern.h
@@ -32,7 +32,6 @@
#ifndef __SOUND_INTERN_H__
#define __SOUND_INTERN_H__
-struct wmOperatorType;
#endif /* __SOUND_INTERN_H__ */
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index f3c6781b0fa..8a3b48125d0 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -51,6 +51,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_library.h"
#include "BKE_packedFile.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
@@ -100,13 +101,14 @@ static int sound_open_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
RNA_string_get(op->ptr, "filepath", path);
- sound = sound_new_file(bmain, path);
+ sound = BKE_sound_new_file(bmain, path);
if (!op->customdata)
sound_open_init(C, op);
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
if (op->customdata) MEM_freeN(op->customdata);
+ BKE_libblock_free(bmain, sound);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
@@ -114,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- sound_delete(bmain, sound);
+ BKE_sound_delete(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
@@ -122,11 +124,11 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "mono")) {
sound->flags |= SOUND_FLAGS_MONO;
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
}
if (RNA_boolean_get(op->ptr, "cache")) {
- sound_cache(sound);
+ BKE_sound_cache(sound);
}
/* hook into UI */
@@ -690,7 +692,7 @@ static int sound_pack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
sound->packedfile = newPackedFile(op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id));
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index 50cf84079d2..68e56490217 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -36,6 +36,7 @@ set(INC_SYS
)
set(SRC
+ action_data.c
action_draw.c
action_edit.c
action_ops.c
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
new file mode 100644
index 00000000000..6e3e456f67d
--- /dev/null
+++ b/source/blender/editors/space_action/action_data.c
@@ -0,0 +1,908 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_action/action_data.c
+ * \ingroup spaction
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mask_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_scene.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "UI_view2d.h"
+
+#include "ED_anim_api.h"
+#include "ED_gpencil.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+#include "ED_screen.h"
+#include "ED_markers.h"
+#include "ED_mask.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "action_intern.h"
+
+/* ************************************************************************** */
+/* ACTION CREATION */
+
+/* Helper function to find the active AnimData block from the Action Editor context */
+AnimData *ED_actedit_animdata_from_context(bContext *C)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+ AnimData *adt = NULL;
+
+ /* Get AnimData block to use */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* Currently, "Action Editor" means object-level only... */
+ if (ob) {
+ adt = ob->adt;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ adt = key->adt;
+ }
+ }
+
+ return adt;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Create new action */
+static bAction *action_create_new(bContext *C, bAction *oldact)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ bAction *action;
+
+ /* create action - the way to do this depends on whether we've got an
+ * existing one there already, in which case we make a copy of it
+ * (which is useful for "versioning" actions within the same file)
+ */
+ if (oldact && GS(oldact->id.name) == ID_AC) {
+ /* make a copy of the existing action */
+ action = BKE_action_copy(oldact);
+ }
+ else {
+ /* just make a new (empty) action */
+ action = add_empty_action(CTX_data_main(C), "Action");
+ }
+
+ /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
+ * but the RNA pointer code will assign all the proper users instead, so we compensate
+ * for that here
+ */
+ BLI_assert(action->id.us == 1);
+ action->id.us--;
+
+ /* set ID-Root type */
+ if (sa->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+
+ if (saction->mode == SACTCONT_SHAPEKEY)
+ action->idroot = ID_KE;
+ else
+ action->idroot = ID_OB;
+ }
+
+ return action;
+}
+
+/* Change the active action used by the action editor */
+static void actedit_change_action(bContext *C, bAction *act)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers and get the property */
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* NOTE: act may be NULL here, so better to just use a cast here */
+ RNA_id_pointer_create((ID *)act, &idptr);
+
+ /* set the new pointer, and force a refresh */
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+}
+
+/* ******************** New Action Operator *********************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
+ * OR
+ * The NLA Editor is active (i.e. Animation Data panel -> new action)
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_new_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* XXX: This assumes that actions are assigned to the active object in this mode */
+ if (ob) {
+ if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ }
+ else if (ED_operator_nla_active(C)) {
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* hook into UI */
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+
+ if (prop) {
+ bAction *action = NULL, *oldact = NULL;
+ AnimData *adt = NULL;
+ PointerRNA oldptr;
+
+ oldptr = RNA_property_pointer_get(&ptr, prop);
+ oldact = (bAction *)oldptr.id.data;
+
+ /* stash the old action to prevent it from being lost */
+ if (ptr.type == &RNA_AnimData) {
+ adt = ptr.data;
+ }
+ else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ adt = ED_actedit_animdata_from_context(C);
+ }
+
+ /* Perform stashing operation - But only if there is an action */
+ if (adt && oldact) {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already
+ * (and unlink the action from the AnimData action slot).
+ * Hence, we must unset the ref to the action in the
+ * action editor too (if this is where we're being called from)
+ * first before setting the new action once it is created,
+ * or else the user gets decremented twice!
+ */
+ if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ SpaceAction *saction = (SpaceAction *)ptr.data;
+ saction->action = NULL;
+ }
+ }
+ else {
+ //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
+ }
+ }
+
+ /* create action */
+ action = action_create_new(C, oldact);
+
+ /* set this new action
+ * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
+ */
+ RNA_id_pointer_create(&action->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+ }
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Action";
+ ot->idname = "ACTION_OT_new";
+ ot->description = "Create new action";
+
+ /* api callbacks */
+ ot->exec = action_new_exec;
+ ot->poll = action_new_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Push-Down Operator ******************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) There must be an action active
+ * 3) The associated AnimData block must not be in tweakmode
+ */
+static int action_pushdown_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for AnimData, Actions, and that tweakmode is off */
+ if (adt && saction->action) {
+ /* NOTE: We check this for the AnimData block in question and not the global flag,
+ * as the global flag may be left dirty by some of the browsing ops here.
+ */
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_pushdown_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Do the deed... */
+ if (adt) {
+ /* Perform the pushdown operation
+ * - This will deal with all the AnimData-side usercounts
+ */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* action can be safely added */
+ BKE_nla_action_pushdown(adt);
+ }
+
+ /* Stop displaying this action in this editor
+ * NOTE: The editor itself doesn't set a user...
+ */
+ saction->action = NULL;
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_push_down(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Push Down Action";
+ ot->idname = "ACTION_OT_push_down";
+ ot->description = "Push action down on to the NLA stack as a new strip";
+
+ /* callbacks */
+ ot->exec = action_pushdown_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Stash Operator ******************** */
+
+static int action_stash_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Perform stashing operation */
+ if (adt) {
+ /* don't do anything if this action is empty... */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ }
+
+ /* clear action refs from editor, and then also the backing data (not necessary) */
+ actedit_change_action(C, NULL);
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
+
+ /* callbacks */
+ ot->exec = action_stash_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action",
+ "Create a new action once the existing one has been safely stored");
+}
+
+/* ----------------- */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_stash_create_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (adt) {
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ else {
+ /* There may not be any action/animdata yet, so, just fallback to the global setting
+ * (which may not be totally valid yet if the action editor was used and things are
+ * now in an inconsistent state)
+ */
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_stash_create_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for no action... */
+ if (saction->action == NULL) {
+ /* just create a new action */
+ bAction *action = action_create_new(C, NULL);
+ actedit_change_action(C, action);
+ }
+ else if (adt) {
+ /* Perform stashing operation */
+ if (action_has_motion(adt->action) == 0) {
+ /* don't do anything if this action is empty... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ bAction *new_action = NULL;
+
+ /* create new action not based on the old one (since the "new" operator already does that) */
+ new_action = action_create_new(C, NULL);
+
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ actedit_change_action(C, new_action);
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ actedit_change_action(C, NULL);
+ }
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash_and_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash_and_create";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
+
+ /* callbacks */
+ ot->exec = action_stash_create_exec;
+ ot->poll = action_stash_create_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
+/* ACTION UNLINK */
+
+/* ******************* Action Unlink Operator ******************** */
+/* We use a custom unlink operator here, as there are some technicalities which need special care:
+ * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action,
+ * or else, everything turns to custard.
+ * 2) If the Action doesn't have any other users, the user should at least get
+ * a warning that it is going to get lost.
+ * 3) We need a convenient way to exit Tweak Mode from the Action Editor
+ */
+
+void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* If the old action only has a single user (that it's about to lose),
+ * warn user about it
+ *
+ * TODO: Maybe we should just save it for them? But then, there's the problem of
+ * trying to get rid of stuff that's actually unwanted!
+ */
+ if (act->id.us == 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
+ act->id.name + 2);
+ }
+
+ /* If in Tweak Mode, don't unlink. Instead, this
+ * becomes a shortcut to exit Tweak Mode instead
+ */
+ if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
+ /* Exit Tweak Mode */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Flush this to the Action Editor (if that's where this change was initiated) */
+ if (sa->spacetype == SPACE_ACTION) {
+ actedit_change_action(C, NULL);
+ }
+ }
+ else {
+ /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
+ if (sa->spacetype == SPACE_ACTION) {
+ /* clear action editor -> action */
+ actedit_change_action(C, NULL);
+ }
+ else {
+ /* clear AnimData -> action */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create AnimData RNA pointers */
+ RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* clear... */
+ RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL);
+ RNA_property_update(C, &ptr, prop);
+ }
+ }
+}
+
+/* -------------------------- */
+
+static int action_unlink_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Only when there's an active action, in the right modes... */
+ if (saction->action && adt)
+ return true;
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_unlink_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ if (adt && adt->action) {
+ ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "ACTION_OT_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->exec = action_unlink_exec;
+ ot->poll = action_unlink_poll;
+}
+
+/* ************************************************************************** */
+/* ACTION BROWSING */
+
+/* Try to find NLA Strip to use for action layer up/down tool */
+static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
+{
+ NlaStrip *strip;
+
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* Can we use this? */
+ if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
+ /* in range - use this one */
+ return strip;
+ }
+ else if ((ctime < strip->start) && (strip->prev == NULL)) {
+ /* before first - use this one */
+ return strip;
+ }
+ else if ((ctime > strip->end) && (strip->next == NULL)) {
+ /* after last - use this one */
+ return strip;
+ }
+ }
+
+ /* nothing suitable found... */
+ return NULL;
+}
+
+/* Switch NLA Strips/Actions */
+static void action_layer_switch_strip(AnimData *adt,
+ NlaTrack *old_track, NlaStrip *old_strip,
+ NlaTrack *nlt, NlaStrip *strip)
+{
+ /* Exit tweakmode on old strip
+ * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ if (old_strip) {
+ old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ }
+ if (old_track) {
+ old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED);
+ }
+
+ /* Make this one the active one instead */
+ strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ nlt->flag |= NLATRACK_ACTIVE;
+
+ /* Copy over "solo" flag - This is useful for stashed actions... */
+ if (old_track) {
+ if (old_track->flag & NLATRACK_SOLO) {
+ old_track->flag &= ~NLATRACK_SOLO;
+ nlt->flag |= NLATRACK_SOLO;
+ }
+ }
+ else {
+ /* NLA muting <==> Solo Tracks */
+ if (adt->flag & ADT_NLA_EVAL_OFF) {
+ /* disable NLA muting */
+ adt->flag &= ~ADT_NLA_EVAL_OFF;
+
+ /* mark this track as being solo */
+ adt->flag |= ADT_NLA_SOLO_TRACK;
+ nlt->flag |= NLATRACK_SOLO;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Enter tweakmode again - hopefully we're now "it" */
+ BKE_nla_tweakmode_enter(adt);
+ BLI_assert(adt->actstrip == strip);
+}
+
+/* ********************** One Layer Up Operator ************************** */
+
+static int action_layer_next_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ /* only allow if we're in tweakmode, and there's something above us... */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* We need to check if there are any tracks above the active one
+ * since the track the action comes from is not stored in AnimData
+ */
+ if (adt->nla_tracks.last) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last;
+
+ if (nlt->flag & NLATRACK_DISABLED) {
+ /* A disabled track will either be the track itself,
+ * or one of the ones above it.
+ *
+ * If this is the top-most one, there is the possibility
+ * that there is no active action. For now, we let this
+ * case return true too, so that there is a natural way
+ * to "move to an empty layer", even though this means
+ * that we won't actually have an action.
+ */
+ // return (adt->tmpact != NULL);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_next_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ if (act_track == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Find next action, and hook it up */
+ if (act_track->next) {
+ NlaTrack *nlt;
+
+ /* Find next action to use */
+ for (nlt = act_track->next; nlt; nlt = nlt->next) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+ }
+ else {
+ /* No more actions (strips) - Go back to editing the original active action
+ * NOTE: This will mean exiting tweakmode...
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Deal with solo flags...
+ * Assume: Solo Track == NLA Muting
+ */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* turn off solo flags on tracks */
+ act_track->flag &= ~NLATRACK_SOLO;
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+
+ /* turn on NLA muting (to keep same effect) */
+ adt->flag |= ADT_NLA_EVAL_OFF;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_next(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Next Layer";
+ ot->idname = "ACTION_OT_layer_next";
+ ot->description = "Switch to editing action in animation layer above the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_next_exec;
+ ot->poll = action_layer_next_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************* One Layer Down Operator ************************* */
+
+static int action_layer_prev_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* Tweak Mode: We need to check if there are any tracks below the active one that we can move to */
+ if (adt->nla_tracks.first) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first;
+
+ /* Since the first disabled track is the track being tweaked/edited,
+ * we can simplify things by only checking the first track:
+ * - If it is disabled, this is the track being tweaked,
+ * so there can't be anything below it
+ * - Otherwise, there is at least 1 track below the tweaking
+ * track that we can descend to
+ */
+ if ((nlt->flag & NLATRACK_DISABLED) == 0) {
+ /* not disabled = there are actions below the one being tweaked */
+ return true;
+ }
+ }
+ }
+ else {
+ /* Normal Mode: If there are any tracks, we can try moving to those */
+ return (adt->nla_tracks.first != NULL);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_prev_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+ NlaTrack *nlt;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Sanity Check */
+ if (adt == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ /* If there is no active track, that means we are using the active action... */
+ if (act_track) {
+ /* Active Track - Start from the one below it */
+ nlt = act_track->prev;
+ }
+ else {
+ /* Active Action - Use the top-most track */
+ nlt = adt->nla_tracks.last;
+ }
+
+ /* Find previous action and hook it up */
+ for (; nlt; nlt = nlt->prev) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_prev(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Previous Layer";
+ ot->idname = "ACTION_OT_layer_prev";
+ ot->description = "Switch to editing action in animation layer below the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_prev_exec;
+ ot->poll = action_layer_prev_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index a17cfa4d87c..10748c2fe15 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -93,6 +93,8 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -104,11 +106,12 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
@@ -210,7 +213,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int sel = 0;
/* determine if any need to draw channel */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 76c955d8bca..90c38426164 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -80,418 +80,6 @@
#include "action_intern.h"
-/* ************************************************************************** */
-/* ACTION MANAGEMENT */
-
-/* Helper function to find the active AnimData block from the Action Editor context */
-static AnimData *actedit_animdata_from_context(bContext *C)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Object *ob = CTX_data_active_object(C);
- AnimData *adt = NULL;
-
- /* Get AnimData block to use */
- if (saction->mode == SACTCONT_ACTION) {
- /* Currently, "Action Editor" means object-level only... */
- adt = ob->adt;
- }
- else if (saction->mode == SACTCONT_SHAPEKEY) {
- Key *key = BKE_key_from_object(ob);
- adt = key->adt;
- }
-
- return adt;
-}
-
-/* Create new action */
-static bAction *action_create_new(bContext *C, bAction *oldact)
-{
- ScrArea *sa = CTX_wm_area(C);
- bAction *action;
-
- /* create action - the way to do this depends on whether we've got an
- * existing one there already, in which case we make a copy of it
- * (which is useful for "versioning" actions within the same file)
- */
- if (oldact && GS(oldact->id.name) == ID_AC) {
- /* make a copy of the existing action */
- action = BKE_action_copy(oldact);
- }
- else {
- /* just make a new (empty) action */
- action = add_empty_action(CTX_data_main(C), "Action");
- }
-
- /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
- * but the RNA pointer code will assign all the proper users instead, so we compensate
- * for that here
- */
- BLI_assert(action->id.us == 1);
- action->id.us--;
-
- /* set ID-Root type */
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
-
- if (saction->mode == SACTCONT_SHAPEKEY)
- action->idroot = ID_KE;
- else
- action->idroot = ID_OB;
- }
-
- return action;
-}
-
-/* Change the active action used by the action editor */
-static void actedit_change_action(bContext *C, bAction *act)
-{
- bScreen *screen = CTX_wm_screen(C);
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
-
- PointerRNA ptr, idptr;
- PropertyRNA *prop;
-
- /* create RNA pointers and get the property */
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
- prop = RNA_struct_find_property(&ptr, "action");
-
- /* NOTE: act may be NULL here, so better to just use a cast here */
- RNA_id_pointer_create((ID *)act, &idptr);
-
- /* set the new pointer, and force a refresh */
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
-}
-
-/* ******************** New Action Operator *********************** */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
- * OR
- * The NLA Editor is active (i.e. Animation Data panel -> new action)
- * 2) The associated AnimData block must not be in tweakmode
- */
-static int action_new_poll(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
-
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
- /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
- if (!(scene->flag & SCE_NLA_EDIT_ON)) {
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
-
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
- }
- else if (ED_operator_nla_active(C)) {
- return true;
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
-{
- PointerRNA ptr, idptr;
- PropertyRNA *prop;
-
- /* hook into UI */
- UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
-
- if (prop) {
- bAction *action = NULL, *oldact = NULL;
- AnimData *adt = NULL;
- PointerRNA oldptr;
-
- oldptr = RNA_property_pointer_get(&ptr, prop);
- oldact = (bAction *)oldptr.id.data;
-
- /* stash the old action to prevent it from being lost */
- if (ptr.type == &RNA_AnimData) {
- adt = ptr.data;
- }
- else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
- adt = actedit_animdata_from_context(C);
- }
-
- /* Perform stashing operation - But only if there is an action */
- if (adt && oldact) {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- /* The stash operation will remove the user already
- * (and unlink the action from the AnimData action slot).
- * Hence, we must unset the ref to the action in the
- * action editor too (if this is where we're being called from)
- * first before setting the new action once it is created,
- * or else the user gets decremented twice!
- */
- if (ptr.type == &RNA_SpaceDopeSheetEditor) {
- SpaceAction *saction = (SpaceAction *)ptr.data;
- saction->action = NULL;
- }
- }
- else {
- //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
- }
- }
-
- /* create action */
- action = action_create_new(C, oldact);
-
- /* set this new action
- * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
- */
- RNA_id_pointer_create(&action->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
- }
-
- /* set notifier that keyframes have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_new(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "New Action";
- ot->idname = "ACTION_OT_new";
- ot->description = "Create new action";
-
- /* api callbacks */
- ot->exec = action_new_exec;
- ot->poll = action_new_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Action Push-Down Operator ******************** */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) There must be an action active
- * 3) The associated AnimData block must not be in tweakmode
- */
-static int action_pushdown_poll(bContext *C)
-{
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
-
- /* Check for actions and that tweakmode is off */
- if ((saction->action) && !(scene->flag & SCE_NLA_EDIT_ON)) {
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- if (saction->mode == SACTCONT_ACTION) {
- return (ob->adt != NULL);
- }
- else if (saction->mode == SACTCONT_SHAPEKEY) {
- Key *key = BKE_key_from_object(ob);
-
- return (key && key->adt);
- }
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_pushdown_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Do the deed... */
- if (adt) {
- /* Perform the pushdown operation
- * - This will deal with all the AnimData-side usercounts
- */
- if (action_has_motion(adt->action) == 0) {
- /* action may not be suitable... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* action can be safely added */
- BKE_nla_action_pushdown(adt);
- }
-
- /* Stop displaying this action in this editor
- * NOTE: The editor itself doesn't set a user...
- */
- saction->action = NULL;
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_push_down(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Push Down Action";
- ot->idname = "ACTION_OT_push_down";
- ot->description = "Push action down on to the NLA stack as a new strip";
-
- /* callbacks */
- ot->exec = action_pushdown_exec;
- ot->poll = action_pushdown_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Action Stash Operator ******************** */
-
-static int action_stash_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Perform stashing operation */
- if (adt) {
- /* don't do anything if this action is empty... */
- if (action_has_motion(adt->action) == 0) {
- /* action may not be suitable... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- /* The stash operation will remove the user already,
- * so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
- * first before setting the new action.
- */
- saction->action = NULL;
- }
- else {
- /* action has already been added - simply warn about this, and clear */
- BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
- }
-
- /* clear action refs from editor, and then also the backing data (not necessary) */
- actedit_change_action(C, NULL);
- }
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_stash(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Stash Action";
- ot->idname = "ACTION_OT_stash";
- ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
-
- /* callbacks */
- ot->exec = action_stash_exec;
- ot->poll = action_pushdown_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action",
- "Create a new action once the existing one has been safely stored");
-}
-
-/* ----------------- */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) The associated AnimData block must not be in tweakmode
- */
-static int action_stash_create_poll(bContext *C)
-{
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Scene *scene = CTX_data_scene(C);
-
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
- /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
- if (!(scene->flag & SCE_NLA_EDIT_ON)) {
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_stash_create_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Check for no action... */
- if (saction->action == NULL) {
- /* just create a new action */
- bAction *action = action_create_new(C, NULL);
- actedit_change_action(C, action);
- }
- else if (adt) {
- /* Perform stashing operation */
- if (action_has_motion(adt->action) == 0) {
- /* don't do anything if this action is empty... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- bAction *new_action = NULL;
-
- /* create new action not based on the old one (since the "new" operator already does that) */
- new_action = action_create_new(C, NULL);
-
- /* The stash operation will remove the user already,
- * so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
- * first before setting the new action.
- */
- saction->action = NULL;
- actedit_change_action(C, new_action);
- }
- else {
- /* action has already been added - simply warn about this, and clear */
- BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
- actedit_change_action(C, NULL);
- }
- }
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_stash_and_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Stash Action";
- ot->idname = "ACTION_OT_stash_and_create";
- ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
-
- /* callbacks */
- ot->exec = action_stash_create_exec;
- ot->poll = action_stash_create_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
/* ************************************************************************** */
/* POSE MARKERS STUFF */
@@ -738,7 +326,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -837,7 +425,15 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
/* only selected */
return actkeys_viewall(C, true);
}
-
+
+static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
void ACTION_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -868,6 +464,21 @@ void ACTION_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+void ACTION_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "ACTION_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = actkeys_view_frame_exec;
+ ot->poll = ED_operator_action_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************************************************************** */
/* GENERAL STUFF */
@@ -1068,8 +679,13 @@ static void insert_action_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
@@ -1142,7 +758,7 @@ static void duplicate_action_keys(bAnimContext *ac)
/* loop through filtered data and delete selected keys */
for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
duplicate_fcurve_keys((FCurve *)ale->key_data);
else if (ale->type == ANIMTYPE_GPLAYER)
ED_gplayer_frames_duplicate((bGPDlayer *)ale->data);
@@ -1176,13 +792,6 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-
-static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- actkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
void ACTION_OT_duplicate(wmOperatorType *ot)
{
@@ -1192,7 +801,6 @@ void ACTION_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = actkeys_duplicate_invoke;
ot->exec = actkeys_duplicate_exec;
ot->poll = ED_operator_action_active;
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 61d4249ae20..17f1f404225 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -35,10 +35,7 @@ struct bContext;
struct bAnimContext;
struct SpaceAction;
struct ARegion;
-struct wmWindowManager;
struct wmOperatorType;
-struct ActKeysInc;
-struct bAnimListElem;
/* internal exports only */
@@ -80,6 +77,7 @@ enum eActKeys_ColumnSelect_Mode {
void ACTION_OT_previewrange_set(struct wmOperatorType *ot);
void ACTION_OT_view_all(struct wmOperatorType *ot);
void ACTION_OT_view_selected(struct wmOperatorType *ot);
+void ACTION_OT_view_frame(struct wmOperatorType *ot);
void ACTION_OT_copy(struct wmOperatorType *ot);
void ACTION_OT_paste(struct wmOperatorType *ot);
@@ -101,10 +99,15 @@ void ACTION_OT_snap(struct wmOperatorType *ot);
void ACTION_OT_mirror(struct wmOperatorType *ot);
void ACTION_OT_new(struct wmOperatorType *ot);
+void ACTION_OT_unlink(struct wmOperatorType *ot);
+
void ACTION_OT_push_down(struct wmOperatorType *ot);
void ACTION_OT_stash(struct wmOperatorType *ot);
void ACTION_OT_stash_and_create(struct wmOperatorType *ot);
+void ACTION_OT_layer_next(struct wmOperatorType *ot);
+void ACTION_OT_layer_prev(struct wmOperatorType *ot);
+
void ACTION_OT_markers_make_local(struct wmOperatorType *ot);
/* defines for snap keyframes
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index 8c706d8da57..59b147c6f6c 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -79,14 +79,20 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_paste);
WM_operatortype_append(ACTION_OT_new);
+ WM_operatortype_append(ACTION_OT_unlink);
+
WM_operatortype_append(ACTION_OT_push_down);
WM_operatortype_append(ACTION_OT_stash);
WM_operatortype_append(ACTION_OT_stash_and_create);
+ WM_operatortype_append(ACTION_OT_layer_next);
+ WM_operatortype_append(ACTION_OT_layer_prev);
+
WM_operatortype_append(ACTION_OT_previewrange_set);
WM_operatortype_append(ACTION_OT_view_all);
WM_operatortype_append(ACTION_OT_view_selected);
-
+ WM_operatortype_append(ACTION_OT_view_frame);
+
WM_operatortype_append(ACTION_OT_markers_make_local);
}
@@ -101,6 +107,7 @@ void ED_operatormacros_action(void)
WM_operatortype_macro_define(ot, "ACTION_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
/* ************************** registration - keymaps **********************************/
@@ -197,11 +204,10 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0);
/* destructive */
- WM_keymap_add_item(keymap, "ACTION_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
@@ -223,6 +229,8 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ACTION_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* animation module */
/* channels list
@@ -236,6 +244,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_action");
+
/* special markers hotkeys for anim editors: see note in definition of this function */
ED_marker_keymap_animedit_conflictfree(keymap);
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index ddfca98a119..0f94baff082 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1221,11 +1221,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
agrp->flag |= AGRP_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
}
- else if (ale->type == ANIMTYPE_FCURVE) {
+ else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = ale->data;
fcu->flag |= FCURVE_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
}
}
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 73091e7f261..bc42f1dd5bb 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -59,6 +59,7 @@
#include "RNA_access.h"
+#include "ED_buttons.h"
#include "ED_armature.h"
#include "ED_screen.h"
#include "ED_physics.h"
@@ -1179,3 +1180,33 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
+
+void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
+{
+ if (sbuts->pinid == id) {
+ sbuts->pinid = NULL;
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+}
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index f294729ae97..7fc35a6b1e7 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -34,7 +34,6 @@
#include "DNA_listBase.h"
#include "RNA_types.h"
-struct ARegion;
struct ARegionType;
struct ID;
struct SpaceButs;
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index ba0c22a4ade..8ad4858ff22 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -97,6 +97,7 @@ void BUTTONS_OT_toolbox(wmOperatorType *ot)
typedef struct FileBrowseOp {
PointerRNA ptr;
PropertyRNA *prop;
+ bool is_undo;
} FileBrowseOp;
static int file_browse_exec(bContext *C, wmOperator *op)
@@ -142,6 +143,10 @@ static int file_browse_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &fbo->ptr, fbo->prop);
MEM_freeN(str);
+ if (fbo->is_undo) {
+ const char *undostr = RNA_property_identifier(fbo->prop);
+ ED_undo_push(C, undostr);
+ }
/* special, annoying exception, filesel on redo panel [#26618] */
{
@@ -168,6 +173,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PointerRNA ptr;
PropertyRNA *prop;
+ bool is_undo;
FileBrowseOp *fbo;
char *str;
@@ -176,7 +182,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- UI_context_active_but_prop_get_filebrowser(C, &ptr, &prop);
+ UI_context_active_but_prop_get_filebrowser(C, &ptr, &prop, &is_undo);
if (!prop)
return OPERATOR_CANCELLED;
@@ -210,6 +216,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
fbo = MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
fbo->ptr = ptr;
fbo->prop = prop;
+ fbo->is_undo = is_undo;
op->customdata = fbo;
RNA_string_set(op->ptr, path_prop, str);
@@ -241,7 +248,8 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
- ot->flag |= OPTYPE_UNDO;
+ /* conditional undo based on button flag */
+ ot->flag = 0;
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
@@ -261,7 +269,8 @@ void BUTTONS_OT_directory_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
- ot->flag |= OPTYPE_UNDO;
+ /* conditional undo based on button flag */
+ ot->flag = 0;
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 6c55d8d034e..76954ede522 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -43,6 +43,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_math_base.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_image.h"
@@ -285,6 +286,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
MovieClip *clip = ED_space_clip_get_clip(sc);
int filter = GL_LINEAR;
int x, y;
+ rctf frame;
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
@@ -308,10 +310,14 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y);
glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter);
-
/* reset zoom */
glPixelZoom(1.0f, 1.0f);
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+
+ if (sc->flag & SC_SHOW_METADATA)
+ ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
+
if (ibuf->planes == 32)
glDisable(GL_BLEND);
}
@@ -1123,7 +1129,9 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
{
bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
bool is_selected_track = (plane_track->flag & SELECT) != 0;
- bool draw_plane_quad = plane_track->image == NULL || plane_track->image_opacity == 0.0f;
+ const bool has_image = plane_track->image != NULL &&
+ BKE_image_has_ibuf(plane_track->image, NULL);
+ const bool draw_plane_quad = !has_image || plane_track->image_opacity == 0.0f;
float px[2];
if (draw_outline) {
@@ -1692,29 +1700,29 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
}
if (sc->flag & SC_SHOW_STABLE) {
+ float translation[2];
+ float aspect = clip->tracking.camera.pixel_aspect;
float smat[4][4], ismat[4][4];
- ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc, &sc->scale, &sc->angle);
-
- if (ibuf) {
- float translation[2];
- float aspect = clip->tracking.camera.pixel_aspect;
+ if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
+ ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc,
+ &sc->scale, &sc->angle);
+ }
- if (width != ibuf->x)
- mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
- else
- copy_v2_v2(translation, sc->loc);
+ if (ibuf != NULL && width != ibuf->x)
+ mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
+ else
+ copy_v2_v2(translation, sc->loc);
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect,
- translation, sc->scale, sc->angle, sc->stabmat);
+ BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation,
+ sc->scale, sc->angle, sc->stabmat);
- unit_m4(smat);
- smat[0][0] = 1.0f / width;
- smat[1][1] = 1.0f / height;
- invert_m4_m4(ismat, smat);
+ unit_m4(smat);
+ smat[0][0] = 1.0f / width;
+ smat[1][1] = 1.0f / height;
+ invert_m4_m4(ismat, smat);
- mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
- }
+ mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
}
else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
ibuf = ED_space_clip_get_buffer(sc);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 89693a403fe..dbedfaa1de4 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -52,6 +52,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_context.h"
#include "BKE_tracking.h"
@@ -64,6 +65,7 @@
#include "ED_screen.h"
#include "ED_clip.h"
+#include "ED_mask.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -219,6 +221,7 @@ int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
+ /* Caller must ensure space does have a valid clip, otherwise it will crash, see T45017. */
return BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
}
@@ -329,7 +332,7 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
}
}
-static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2])
+static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTrackingTrack *track;
@@ -377,6 +380,29 @@ static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2])
return ok;
}
+static bool selected_boundbox(const bContext *C, float min[2], float max[2])
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc->mode == SC_MODE_TRACKING) {
+ return selected_tracking_boundbox(sc, min, max);
+ }
+ else {
+ if (ED_mask_selected_minmax(C, min, max)) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int width, height;
+ ED_space_clip_get_size(sc, &width, &height);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
+ BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
+ min[0] *= width;
+ min[1] *= height;
+ max[0] *= width;
+ max[1] *= height;
+ return true;
+ }
+ return false;
+ }
+}
+
bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -388,7 +414,7 @@ bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL))
return false;
- if (!selected_boundbox(sc, min, max))
+ if (!selected_boundbox(C, min, max))
return false;
/* center view */
@@ -626,8 +652,9 @@ static bool check_prefetch_break(void)
}
/* read file for specified frame number to the memory */
-static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_frame, short render_size,
- short render_flag, size_t *size_r)
+static unsigned char *prefetch_read_file_to_memory(
+ MovieClip *clip, int current_frame, short render_size, short render_flag,
+ size_t *r_size)
{
MovieClipUser user = {0};
char name[FILE_MAX];
@@ -660,7 +687,7 @@ static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_
return NULL;
}
- *size_r = size;
+ *r_size = size;
close(file);
@@ -698,8 +725,9 @@ static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end
}
/* get memory buffer for first uncached frame within prefetch frame range */
-static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip *clip,
- size_t *size_r, int *current_frame_r)
+static unsigned char *prefetch_thread_next_frame(
+ PrefetchQueue *queue, MovieClip *clip,
+ size_t *r_size, int *r_current_frame)
{
unsigned char *mem = NULL;
@@ -728,9 +756,9 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip
int frames_processed;
mem = prefetch_read_file_to_memory(clip, current_frame, queue->render_size,
- queue->render_flag, size_r);
+ queue->render_flag, r_size);
- *current_frame_r = current_frame;
+ *r_current_frame = current_frame;
queue->current_frame = current_frame;
@@ -765,13 +793,15 @@ static void prefetch_task_func(TaskPool *pool, void *task_data, int UNUSED(threa
int flag = IB_rect | IB_alphamode_detect;
int result;
char *colorspace_name = NULL;
+ const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
+ (queue->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
user.framenr = current_frame;
user.render_size = queue->render_size;
user.render_flag = queue->render_flag;
/* Proxies are stored in the display space. */
- if (queue->render_flag & MCLIP_USE_PROXY) {
+ if (!use_proxy) {
colorspace_name = clip->colorspace_settings.name;
}
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index 2a2f15c94bb..e781d199d35 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -200,10 +200,18 @@ static bool mouse_select_knot(bContext *C, float co[2], bool extend)
toggle_selection_cb);
}
- if (userdata.coord == 0)
- userdata.marker->flag |= MARKER_GRAPH_SEL_X;
- else
- userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ if (userdata.coord == 0) {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_X;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_X;
+ }
+ else {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ }
return true;
}
@@ -238,10 +246,12 @@ static bool mouse_select_curve(bContext *C, float co[2], bool extend)
else if (act_track != userdata.track) {
SelectUserData selectdata = {SEL_DESELECT};
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
tracking->act_track = userdata.track;
- BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, true);
+ if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
+ }
/* deselect all knots on newly selected curve */
clip_graph_tracking_iterate(sc,
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 322825ccc84..1d398177d9f 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -658,7 +658,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -912,7 +912,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 5f919c9b51d..48f8f587106 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -177,9 +177,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingPlaneTrack *plane_track, *next_plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
bool has_bundle = false, update_stab = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
@@ -197,49 +195,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
has_bundle = true;
/* Make sure no plane will use freed track */
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = next_plane_track)
- {
- bool found = false;
- int i;
-
- next_plane_track = plane_track->next;
-
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == track) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- continue;
- }
-
- if (plane_track->point_tracksnr > 4) {
- int track_index;
- MovieTrackingTrack **new_point_tracks;
-
- new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr,
- "new point tracks array");
-
- for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] != track) {
- new_point_tracks[track_index++] = plane_track->point_tracks[i];
- }
- }
-
- MEM_freeN(plane_track->point_tracks);
- plane_track->point_tracks = new_point_tracks;
- plane_track->point_tracksnr--;
- }
- else {
- /* Delete planes with less than 3 point tracks in it. */
- BKE_tracking_plane_track_free(plane_track);
- BLI_freelinkN(plane_tracks_base, plane_track);
- }
- }
+ BKE_tracking_plane_tracks_remove_point_track(tracking, track);
/* Delete f-curves associated with the track (such as weight, i.e.) */
BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index fc2c0d3d45c..5ba82f7f71f 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -206,7 +206,7 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
if (sc->mode != SC_MODE_TRACKING)
return;
- /* only while proeprties are visible */
+ /* only while properties are visible */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_UI && ar->flag & RGN_FLAG_HIDDEN)
return;
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 742e58d80dd..91e11d30cc2 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -825,12 +825,8 @@ static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
plane_track = plane_track->next)
{
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == data->track) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- break;
- }
+ if (BKE_tracking_plane_track_has_point_track(plane_track, data->track)) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
}
}
}
@@ -1070,7 +1066,7 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
ot->modal = slide_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -1430,6 +1426,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
}
clip = ED_space_clip_get_clip(sc);
+ BLI_assert(clip != NULL);
framenr = ED_space_clip_get_clip_frame_number(sc);
if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
@@ -1508,6 +1505,7 @@ void CLIP_OT_track_markers(wmOperatorType *ot)
ot->exec = track_markers_exec;
ot->invoke = track_markers_invoke;
ot->modal = track_markers_modal;
+ ot->poll = ED_space_clip_tracking_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -1883,7 +1881,7 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
RNA_def_boolean(ot->srna, "clear_active", 0, "Clear Active", "Clear active track only instead of all selected tracks");
}
@@ -2042,7 +2040,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat
bool found = false;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -2073,7 +2071,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob)
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -3054,7 +3052,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
if (CFRA != sc->user.framenr) {
CFRA = sc->user.framenr;
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -3117,6 +3115,12 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (tracking->stabilization.rot_track == track)
tracking->stabilization.rot_track = act_track;
+ /* TODO(sergey): Re-evaluate planes with auto-key. */
+ BKE_tracking_plane_tracks_replace_point_track(tracking,
+ track,
+ act_track);
+
+
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
}
@@ -4181,7 +4185,7 @@ void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
ot->modal = slide_plane_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
}
/********************** Insert track keyframe operator *********************/
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 0b29c253f3a..8a2bf17c667 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -997,6 +997,6 @@ void CLIP_OT_select_grouped(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
}
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index a3746e091ce..d8a4a6fd2bb 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -31,7 +31,6 @@
struct ConsoleLine;
struct wmOperatorType;
-struct ReportList;
struct bContext;
/* console_draw.c */
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index fc007a659b4..4c33499da41 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
file_draw.c
file_ops.c
file_panels.c
+ file_utils.c
filelist.c
filesel.c
fsmenu.c
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 98c7ddeff77..6347ce7c4e8 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -295,22 +295,29 @@ static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon,
static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align)
{
- uiStyle *style = UI_style_get();
- uiFontStyle fs = style->widgetlabel;
+ uiStyle *style;
+ uiFontStyle fs;
rcti rect;
char fname[FILE_MAXFILE];
+ if (string[0] == '\0') {
+ return;
+ }
+
+ style = UI_style_get();
+ fs = style->widgetlabel;
+
fs.align = align;
BLI_strncpy(fname, string, FILE_MAXFILE);
- file_shorten_string(fname, width + 1.0f, 0);
+ UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0');
/* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 4.0f));
+ rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
rect.ymin = sy - height;
rect.ymax = sy;
-
+
UI_fontstyle_draw(&fs, &rect, fname);
}
@@ -323,35 +330,40 @@ void file_calc_previews(const bContext *C, ARegion *ar)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
-static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool dropshadow, bool drag)
+static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool is_icon, bool drag)
{
uiBut *but;
float fx, fy;
float dx, dy;
int xco, yco;
+ float ui_imbx, ui_imby;
float scaledx, scaledy;
float scale;
int ex, ey;
+ bool use_dropshadow = !is_icon && (file->flags & FILE_TYPE_IMAGE);
BLI_assert(imb != NULL);
- if ((imb->x * UI_DPI_FAC > layout->prv_w) ||
- (imb->y * UI_DPI_FAC > layout->prv_h))
+ ui_imbx = imb->x * UI_DPI_FAC;
+ ui_imby = imb->y * UI_DPI_FAC;
+ /* Unlike thumbnails, icons are not scaled up. */
+ if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) ||
+ (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h))))
{
if (imb->x > imb->y) {
scaledx = (float)layout->prv_w;
- scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w;
+ scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w;
scale = scaledx / imb->x;
}
else {
scaledy = (float)layout->prv_h;
- scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h;
+ scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h;
scale = scaledy / imb->y;
}
}
else {
- scaledx = (float)imb->x * UI_DPI_FAC;
- scaledy = (float)imb->y * UI_DPI_FAC;
+ scaledx = ui_imbx;
+ scaledy = ui_imby;
scale = UI_DPI_FAC;
}
@@ -367,17 +379,23 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* shadow */
- if (dropshadow)
+ if (use_dropshadow) {
UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ }
glEnable(GL_BLEND);
/* the image */
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ if (!is_icon && file->flags & FILE_TYPE_FTFONT) {
+ UI_ThemeColor(TH_TEXT);
+ }
+ else {
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ }
glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
/* border */
- if (dropshadow) {
+ if (use_dropshadow) {
glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
}
@@ -525,9 +543,9 @@ void file_draw_list(const bContext *C, ARegion *ar)
if (!(file->selflag & FILE_SEL_EDITING)) {
- if ((params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) {
+ if ((params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) {
int colorid = (file->selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
- int shade = (params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0;
+ int shade = (params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0;
/* readonly files (".." and ".") must not be drawn as selected - set color back to normal */
if (FILENAME_IS_CURRPAR(file->relname)) {
@@ -549,7 +567,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
is_icon = 1;
}
- file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), do_drag);
+ file_draw_preview(block, file, sx, sy, imb, layout, is_icon, do_drag);
}
else {
file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index e7a6cd62a33..d7af6c9b812 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -59,9 +59,17 @@ bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
struct wmOperatorType;
struct wmOperator;
-struct wmEvent;
+
+typedef enum WalkSelectDirection {
+ FILE_SELECT_WALK_UP,
+ FILE_SELECT_WALK_DOWN,
+ FILE_SELECT_WALK_LEFT,
+ FILE_SELECT_WALK_RIGHT,
+} WalkSelectDirections;
+
void FILE_OT_highlight(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
+void FILE_OT_select_walk(struct wmOperatorType *ot);
void FILE_OT_select_all_toggle(struct wmOperatorType *ot);
void FILE_OT_select_border(struct wmOperatorType *ot);
void FILE_OT_select_bookmark(struct wmOperatorType *ot);
@@ -102,7 +110,6 @@ void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
-float file_shorten_string(char *string, float w, int front);
float file_string_width(const char *str);
float file_font_pointsize(void);
@@ -113,5 +120,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
/* file_panels.c */
void file_panels_register(struct ARegionType *art);
+/* file_utils.c */
+void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
+
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index f8d13bb6adb..8c9233e3ce5 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -176,7 +176,8 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
(selected_idx < numfiles) &&
(file = filelist_file(sfile->files, selected_idx)))
{
- params->active_file = selected_idx;
+ params->highlight_file = selected_idx;
+ sfile->params->active_file = selected_idx;
if (S_ISDIR(file->type)) {
const bool is_parent_dir = FILENAME_IS_PARENT(file->relname);
@@ -214,6 +215,23 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
return retval;
}
+/**
+ * \warning: loops over all files so better use cautiously
+ */
+static bool file_is_any_selected(struct FileList *files)
+{
+ const int numfiles = filelist_numfiles(files);
+ int i;
+
+ for (i = 0; i < numfiles; ++i) {
+ if (filelist_is_selected(files, i, CHECK_ALL)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
{
@@ -229,19 +247,53 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
if (sel.first != sel.last) select = 0;
/* Do we have a valid selection and are we actually selecting */
- if ((sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE))) {
+ if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
/* Check last selection, if selected, act on the file or dir */
if (filelist_is_selected(sfile->files, sel.last, check_type)) {
retval = file_select_do(C, sel.last, do_diropen);
}
}
+ if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
+ sfile->params->active_file = -1;
+ }
+
/* update operator for name change event */
file_draw_check(C);
return retval;
}
+static int file_border_select_find_last_selected(
+ SpaceFile *sfile, ARegion *ar, const FileSelection *sel,
+ const int mouse_xy[2])
+{
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ rcti bounds_first, bounds_last;
+ int dist_first, dist_last;
+
+ file_tile_boundbox(ar, layout, sel->first, &bounds_first);
+ file_tile_boundbox(ar, layout, sel->last, &bounds_last);
+
+ /* are first and last in the same column (horizontal layout)/row (vertical layout)? */
+ if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
+ (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin))
+ {
+ /* use vertical distance */
+ const int my_loc = mouse_xy[1] - ar->winrct.ymin;
+ dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
+ dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
+ }
+ else {
+ /* use horizontal distance */
+ const int mx_loc = mouse_xy[0] - ar->winrct.xmin;
+ dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
+ dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
+ }
+
+ return dist_first < dist_last ? sel->first : sel->last;
+}
+
static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
@@ -276,17 +328,17 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
file->selflag &= ~FILE_SEL_HIGHLIGHTED;
}
- /* active_file gets highlighted as well - make sure it is no readonly file */
+ /* make sure highlight_file is no readonly file */
if (sel.last == idx) {
- params->active_file = idx;
+ params->highlight_file = idx;
}
}
}
params->sel_first = sel.first; params->sel_last = sel.last;
-
+ params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, &event->x);
}
else {
- params->active_file = -1;
+ params->highlight_file = -1;
params->sel_first = params->sel_last = -1;
file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -361,7 +413,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
if (sfile && sfile->params) {
- int idx = sfile->params->active_file;
+ int idx = sfile->params->highlight_file;
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
@@ -409,35 +461,252 @@ void FILE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/**
+ * \returns true if selection has changed
+ */
+static bool file_walk_select_selection_set(
+ bContext *C, SpaceFile *sfile,
+ const int direction, const int numfiles,
+ const int active_old, const int active_new, const int other_site,
+ const bool has_selection, const bool extend, const bool fill)
+{
+ FileSelectParams *params = sfile->params;
+ struct FileList *files = sfile->files;
+ const int last_sel = params->active_file; /* store old value */
+ int active = active_old; /* could use active_old instead, just for readability */
+ bool deselect = false;
+
+ BLI_assert(params);
+
+ if (has_selection) {
+ if (extend &&
+ filelist_is_selected(files, active_old, FILE_SEL_SELECTED) &&
+ filelist_is_selected(files, active_new, FILE_SEL_SELECTED))
+ {
+ /* conditions for deselecting: initial file is selected, new file is
+ * selected and either other_side isn't selected/found or we use fill */
+ deselect = (fill || other_site == -1 || !filelist_is_selected(files, other_site, FILE_SEL_SELECTED));
+
+ /* don't change active here since we either want to deselect active or we want to
+ * walk through a block of selected files without selecting/deselecting anything */
+ params->active_file = active_new;
+ /* but we want to change active if we use fill (needed to get correct selection bounds) */
+ if (deselect && fill) {
+ active = active_new;
+ }
+ }
+ else {
+ /* regular selection change */
+ params->active_file = active = active_new;
+ }
+ }
+ else {
+ /* select last file */
+ if (ELEM(direction, FILE_SELECT_WALK_UP, FILE_SELECT_WALK_LEFT)) {
+ params->active_file = active = numfiles - 1;
+ }
+ /* select first file */
+ else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) {
+ params->active_file = active = 1;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (active < 0) {
+ return false;
+ }
+
+ /* highlight the active walker file for extended selection for better visual feedback */
+ if (extend) {
+ params->highlight_file = params->active_file;
+ }
+ else {
+ /* deselect all first */
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+
+ /* highlight file under mouse pos */
+ params->highlight_file = -1;
+ WM_event_add_mousemove(C);
+ }
+
+ /* do the actual selection */
+ if (fill) {
+ FileSelection sel = { MIN2(active, last_sel), MAX2(active, last_sel) };
+
+ /* fill selection between last and first selected file */
+ filelist_select(
+ files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ /* entire sel is cleared here, so select active again */
+ if (deselect) {
+ filelist_select_file(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+ }
+ else {
+ filelist_select_file(
+ files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+
+ BLI_assert(IN_RANGE(active, 0, numfiles));
+
+ /* selection changed */
+ return true;
+}
+
+/**
+ * \returns true if selection has changed
+ */
+static bool file_walk_select_do(
+ bContext *C, SpaceFile *sfile,
+ FileSelectParams *params, const int direction,
+ const bool extend, const bool fill)
+{
+ struct FileList *files = sfile->files;
+ const int numfiles = filelist_numfiles(files);
+ const bool has_selection = file_is_any_selected(files);
+ const int active_old = params->active_file;
+ int active_new = -1;
+ int other_site = -1; /* file on the other site of active_old */
+
+
+ /* *** get all needed files for handling selection *** */
+
+ if (has_selection) {
+ ARegion *ar = CTX_wm_region(C);
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns;
+
+ if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT))
+ {
+ active_new = active_old - 1;
+ other_site = active_old + 1;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_DOWN) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_RIGHT))
+ {
+ active_new = active_old + 1;
+ other_site = active_old - 1;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_LEFT) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_UP))
+ {
+ active_new = active_old - idx_shift;
+ other_site = active_old + idx_shift;
+ }
+ else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_RIGHT) ||
+ (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_DOWN))
+ {
+
+ active_new = active_old + idx_shift;
+ other_site = active_old - idx_shift;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (!IN_RANGE(active_new, 0, numfiles)) {
+ if (extend) {
+ /* extend to invalid file -> abort */
+ return false;
+ }
+ else {
+ /* select initial file */
+ active_new = active_old;
+ }
+ }
+ if (!IN_RANGE(other_site, 0, numfiles)) {
+ other_site = -1;
+ }
+ }
+
+ return file_walk_select_selection_set(
+ C, sfile, direction, numfiles, active_old, active_new, other_site, has_selection, extend, fill);
+}
+
+static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+ FileSelectParams *params = sfile->params;
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool fill = RNA_boolean_get(op->ptr, "fill");
+
+ if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void FILE_OT_select_walk(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {FILE_SELECT_WALK_UP, "UP", 0, "Prev", ""},
+ {FILE_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""},
+ {FILE_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""},
+ {FILE_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Walk Select/Deselect File";
+ ot->description = "Select/Deselect files by walking through them";
+ ot->idname = "FILE_OT_select_walk";
+
+ /* api callbacks */
+ ot->invoke = file_walk_select_invoke;
+ ot->poll = ED_operator_file_active;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "direction", direction_items, 0, "Walk Direction",
+ "Select/Deselect file in this direction");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend",
+ "Extend selection instead of deselecting everything first");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelection sel;
- int numfiles = filelist_numfiles(sfile->files);
- int i;
- bool is_selected = false;
+ const int numfiles = filelist_numfiles(sfile->files);
+ const bool has_selection = file_is_any_selected(sfile->files);
sel.first = 0;
sel.last = numfiles - 1;
- /* Is any file selected ? */
- for (i = 0; i < numfiles; ++i) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
- is_selected = true;
- break;
- }
- }
/* select all only if previously no file was selected */
- if (is_selected) {
+ if (has_selection) {
filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ sfile->params->active_file = -1;
}
else {
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
+ int i;
+
filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type);
+
+ /* set active_file to first selected */
+ for (i = 0; i < numfiles; i++) {
+ if (filelist_is_selected(sfile->files, i, check_type)) {
+ sfile->params->active_file = i;
+ break;
+ }
+ }
}
+
file_draw_check(C);
+ WM_event_add_mousemove(C);
ED_area_tag_redraw(sa);
+
return OPERATOR_FINISHED;
}
@@ -748,28 +1017,28 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
numfiles = filelist_numfiles(sfile->files);
params = ED_fileselect_get_params(sfile);
- origfile = params->active_file;
+ origfile = params->highlight_file;
mx -= ar->winrct.xmin;
my -= ar->winrct.ymin;
if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) {
float fx, fy;
- int active_file;
+ int highlight_file;
UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
- active_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
+ highlight_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
- if ((active_file >= 0) && (active_file < numfiles))
- params->active_file = active_file;
+ if ((highlight_file >= 0) && (highlight_file < numfiles))
+ params->highlight_file = highlight_file;
else
- params->active_file = -1;
+ params->highlight_file = -1;
}
else
- params->active_file = -1;
+ params->highlight_file = -1;
- return (params->active_file != origfile);
+ return (params->highlight_file != origfile);
}
static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -1669,7 +1938,7 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
- int idx = sfile->params->active_file;
+ int idx = sfile->params->highlight_file;
int numfiles = filelist_numfiles(sfile->files);
if ( (0 <= idx) && (idx < numfiles) ) {
struct direntry *file = filelist_file(sfile->files, idx);
@@ -1690,7 +1959,7 @@ static int file_rename_poll(bContext *C)
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- int idx = sfile->params->active_file;
+ int idx = sfile->params->highlight_file;
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
@@ -1699,7 +1968,7 @@ static int file_rename_poll(bContext *C)
}
}
- if (sfile->params->active_file < 0) {
+ if (sfile->params->highlight_file < 0) {
poll = 0;
}
else {
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
new file mode 100644
index 00000000000..8a80e4a69ee
--- /dev/null
+++ b/source/blender/editors/space_file/file_utils.c
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_file/file_utils.c
+ * \ingroup spfile
+ */
+
+#include "BLI_rect.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_fileselect.h"
+
+#include "WM_types.h"
+
+#include "file_intern.h"
+
+
+void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds)
+{
+ int xmin, ymax;
+
+ ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax);
+ BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
+ ar->winy - ymax - layout->tile_h - layout->tile_border_y, ar->winy - ymax);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 66acd7d05e3..4048c9fc1a1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -654,7 +654,7 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index)
if (file->flags & FILE_TYPE_BLENDER) {
ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
}
- else if ((file->flags & FILE_TYPE_MOVIE) || (file->flags & FILE_TYPE_MOVIE_ICON)) {
+ else if (file->flags & FILE_TYPE_MOVIE) {
ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
}
else if (file->flags & FILE_TYPE_SOUND) {
@@ -900,7 +900,6 @@ static void filelist_setfiletypes(struct FileList *filelist)
file = filelist->filelist;
for (num = 0; num < filelist->numfiles; num++, file++) {
- file->type = file->s.st_mode; /* restore the mess below */
#ifndef __APPLE__
/* Don't check extensions for directories, allow in OSX cause bundles have extensions*/
if (file->type & S_IFDIR) {
@@ -1105,7 +1104,7 @@ static void filelist_from_library(struct FileList *filelist)
previews = NULL;
nprevs = 0;
names = BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
- nnames = BLI_linklist_length(names);
+ nnames = BLI_linklist_count(names);
}
filelist->numfiles = nnames + 1;
@@ -1235,7 +1234,7 @@ static void filelist_from_main(struct FileList *filelist)
files = filelist->filelist;
- if (!filelist->filter_data.hide_parent) {
+ if (files && !filelist->filter_data.hide_parent) {
memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[0].type |= S_IFDIR;
@@ -1247,7 +1246,7 @@ static void filelist_from_main(struct FileList *filelist)
for (id = lb->first; id; id = id->next) {
ok = 1;
if (ok) {
- if (!filelist->filter_data.hide_dot || id->name[2] != '.') {
+ if (files && (!filelist->filter_data.hide_dot || id->name[2] != '.')) {
memset(files, 0, sizeof(struct direntry));
if (id->lib == NULL) {
files->relname = BLI_strdup(id->name + 2);
@@ -1334,20 +1333,23 @@ static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float
tj->do_update = do_update;
while ((*stop == 0) && (limg)) {
+ ThumbSource source = 0;
+
+ BLI_assert(limg->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP));
if (limg->flags & FILE_TYPE_IMAGE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
+ source = THB_SOURCE_IMAGE;
}
else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
+ source = THB_SOURCE_BLEND;
}
else if (limg->flags & FILE_TYPE_MOVIE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
- if (!limg->img) {
- /* remember that file can't be loaded via IMB_open_anim */
- limg->flags &= ~FILE_TYPE_MOVIE;
- limg->flags |= FILE_TYPE_MOVIE_ICON;
- }
+ source = THB_SOURCE_MOVIE;
}
+ else if (limg->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
+ }
+ limg->img = IMB_thumb_manage(limg->path, THB_LARGE, source);
*do_update = true;
PIL_sleep_ms(10);
limg = limg->next;
@@ -1363,11 +1365,6 @@ static void thumbnails_update(void *tjv)
while (limg) {
if (!limg->done && limg->img) {
tj->filelist->filelist[limg->index].image = IMB_dupImBuf(limg->img);
- /* update flag for movie files where thumbnail can't be created */
- if (limg->flags & FILE_TYPE_MOVIE_ICON) {
- tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE;
- tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON;
- }
limg->done = true;
IMB_freeImBuf(limg->img);
limg->img = NULL;
@@ -1408,7 +1405,7 @@ void thumbnails_start(FileList *filelist, const bContext *C)
continue;
}
if (!filelist->filelist[idx].image) {
- if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE |
+ if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))
{
FileImage *limg = MEM_callocN(sizeof(*limg), __func__);
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 797d54a89b1..44e0a5169fa 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -40,12 +40,7 @@ extern "C" {
struct BlendHandle;
struct FileList;
struct FileSelection;
-struct FolderList;
-struct Main;
-struct ReportList;
-struct Scene;
struct direntry;
-struct rcti;
struct wmWindowManager;
typedef enum FileSelType {
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 14b72eb8f6d..66eb79abae2 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -102,6 +102,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
/* set path to most recently opened .blend */
BLI_split_dirfile(G.main->name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
+ /* set the default thumbnails size */
+ sfile->params->thumbnail_size = 128;
}
params = sfile->params;
@@ -248,6 +250,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
/* operator has no setting for this */
params->sort = FILE_SORT_ALPHA;
+ params->active_file = -1;
/* initialize the list with previous folders */
@@ -281,6 +284,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
sfile->params->type = FILE_UNIX;
sfile->params->flag = 0;
sfile->params->title[0] = '\0';
+ sfile->params->active_file = -1;
}
int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
@@ -396,63 +400,23 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/* Shorten a string to a given width w.
- * If front is set, shorten from the front,
- * otherwise shorten from the end. */
-float file_shorten_string(char *string, float w, int front)
-{
- char temp[FILE_MAX];
- short shortened = 0;
- float sw = 0;
- float pad = 0;
-
- if (w <= 0) {
- *string = '\0';
- return 0.0;
- }
+float file_string_width(const char *str)
+{
+ uiStyle *style = UI_style_get();
+ float width;
- sw = file_string_width(string);
- if (front == 1) {
- const char *s = string;
- BLI_strncpy(temp, "...", 4);
- pad = file_string_width(temp);
- while ((*s) && (sw + pad > w)) {
- s++;
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(s);
- BLI_strncpy(temp + 3, s, slen + 1);
- temp[slen + 4] = '\0';
- BLI_strncpy(string, temp, slen + 4);
- }
+ UI_fontstyle_set(&style->widget);
+ if (style->widget.kerning == 1) { /* for BLF_width */
+ BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
- else {
- const char *s = string;
- while (sw > w) {
- int slen = strlen(string);
- string[slen - 1] = '\0';
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(string);
- if (slen > 3) {
- BLI_strncpy(string + slen - 3, "...", 4);
- }
- }
+ width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (style->widget.kerning == 1) {
+ BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
-
- return sw;
-}
-float file_string_width(const char *str)
-{
- uiStyle *style = UI_style_get();
- UI_fontstyle_set(&style->widget);
- return BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ return width;
}
float file_font_pointsize(void)
@@ -527,8 +491,8 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->textheight = textheight;
if (params->display == FILE_IMGDISPLAY) {
- layout->prv_w = 4.8f * UI_UNIT_X;
- layout->prv_h = 4.8f * UI_UNIT_Y;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.3f * UI_UNIT_X;
layout->tile_border_y = 0.3f * UI_UNIT_X;
layout->prv_border_x = 0.3f * UI_UNIT_X;
@@ -642,8 +606,8 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
*/
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
- /* use same rule as 'FileCheckType.CHECK_FILES' */
- if (S_ISREG(file->type) && (fnmatch(pattern, file->relname, 0) == 0)) {
+ /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
+ if (fnmatch(pattern, file->relname, 0) == 0) {
file->selflag |= FILE_SEL_SELECTED;
if (!match) {
BLI_strncpy(matched_file, file->relname, FILE_MAX);
@@ -694,13 +658,8 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
closedir(dir);
match = UI_autocomplete_end(autocpl, str);
- if (match) {
- if (match == AUTOCOMPLETE_FULL_MATCH) {
- BLI_add_slash(str);
- }
- else {
- BLI_strncpy(sfile->params->dir, str, sizeof(sfile->params->dir));
- }
+ if (match == AUTOCOMPLETE_FULL_MATCH) {
+ BLI_add_slash(str);
}
}
}
@@ -740,7 +699,7 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile)
filelist_free(sfile->files);
}
- sfile->params->active_file = -1;
+ sfile->params->highlight_file = -1;
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index c6ee6875403..fdf7b458865 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -565,7 +565,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
+ if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
/* Exclude "all my files" as it makes no sense in blender fileselector */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 782b318b8a2..c7e0e4ad4e9 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -212,7 +212,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
if (!sfile->files) {
sfile->files = filelist_new(params->type);
filelist_setdir(sfile->files, params->dir);
- params->active_file = -1; /* added this so it opens nicer (ton) */
+ params->highlight_file = -1; /* added this so it opens nicer (ton) */
}
filelist_setsorting(sfile->files, params->sort);
filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT,
@@ -377,7 +377,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_ortho(v2d);
/* on first read, find active file */
- if (params->active_file == -1) {
+ if (params->highlight_file == -1) {
wmEvent *event = CTX_wm_window(C)->eventstate;
file_highlight_set(sfile, ar, event->x, event->y);
}
@@ -397,6 +397,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar)
static void file_operatortypes(void)
{
WM_operatortype_append(FILE_OT_select);
+ WM_operatortype_append(FILE_OT_select_walk);
WM_operatortype_append(FILE_OT_select_all_toggle);
WM_operatortype_append(FILE_OT_select_border);
WM_operatortype_append(FILE_OT_select_bookmark);
@@ -462,6 +463,49 @@ static void file_keymap(struct wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "fill", true);
RNA_boolean_set(kmi->ptr, "open", false);
+
+ /* arrow keys navigation (walk selecting) */
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ RNA_boolean_set(kmi->ptr, "fill", true);
+
+
/* front and back mouse folder navigation */
WM_keymap_add_item(keymap, "FILE_OT_previous", BUTTON4MOUSE, KM_CLICK, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index a2b64afdb15..e0b62722d57 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -165,9 +165,28 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
/* user-friendly 'name' for F-Curve */
- /* TODO: only show the path if this is invalid? */
col = uiLayoutColumn(layout, false);
- icon = getname_anim_fcurve(name, ale->id, fcu);
+ if (ale->type == ANIMTYPE_FCURVE) {
+ /* get user-friendly name for F-Curve */
+ icon = getname_anim_fcurve(name, ale->id, fcu);
+ }
+ else {
+ /* NLA Control Curve, etc. */
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+
+ /* get name */
+ if (acf && acf->name) {
+ acf->name(ale, name);
+ }
+ else {
+ strcpy(name, IFACE_("<invalid>"));
+ icon = ICON_ERROR;
+ }
+
+ /* icon */
+ if (ale->type == ANIMTYPE_NLACURVE)
+ icon = ICON_NLA;
+ }
uiItemL(col, name, icon);
/* RNA-Path Editing - only really should be enabled when things aren't working */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index a5c04ce2cb4..87e7cab4d15 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -481,7 +481,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
ChannelDriver *driver;
float samplefreq;
float stime, etime;
- float unitFac;
+ float unitFac, offset;
float dx, dy;
short mapping_flag = ANIM_get_normalization_flags(ac);
int i, n;
@@ -498,7 +498,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
fcu->driver = NULL;
/* compute unit correction factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* Note about sampling frequency:
* Ideally, this is chosen such that we have 1-2 pixels = 1 segment
@@ -550,7 +550,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
n = (etime - stime) / samplefreq + 0.5f;
for (i = 0; i <= n; i++) {
float ctime = stime + i * samplefreq;
- glVertex2f(ctime, evaluate_fcurve(fcu, ctime) * unitFac);
+ glVertex2f(ctime, (evaluate_fcurve(fcu, ctime) + offset) * unitFac);
}
glEnd();
@@ -566,13 +566,14 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
FPoint *fpt = prevfpt + 1;
float fac, v[2];
int b = fcu->totvert - 1;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
glBegin(GL_LINE_STRIP);
@@ -665,14 +666,15 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
float fac = 0.0f;
int b = fcu->totvert - 1;
int resol;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
-
+ glTranslatef(0.0f, offset, 0.0f);
+
glBegin(GL_LINE_STRIP);
/* extrapolate to left? */
@@ -826,7 +828,8 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
ChannelDriver *driver = fcu->driver;
View2D *v2d = &ac->ar->v2d;
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ float offset;
+ float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* for now, only show when debugging driver... */
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
@@ -850,10 +853,10 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glBegin(GL_LINES);
{
t = v2d->cur.xmin;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
t = v2d->cur.xmax;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
}
glEnd();
@@ -1067,10 +1070,12 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
glPushMatrix();
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
if (fcu->bezt) {
bool do_handles = draw_fcurve_handles_check(sipo, fcu);
@@ -1137,6 +1142,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
@@ -1148,11 +1155,12 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2944901663b..3de3ecebc44 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -109,7 +109,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float txmin, txmax, tymin, tymax;
- float unitFac;
+ float unitFac, offset;
/* get range */
if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
@@ -122,7 +122,9 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
}
/* apply unit corrections */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+ tymin += offset;
+ tymax += offset;
tymin *= unitFac;
tymax *= unitFac;
@@ -256,6 +258,14 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
}
+static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
+
void GRAPH_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -294,6 +304,21 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
+void GRAPH_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "GRAPH_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = graphkeys_view_frame_exec;
+ ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ******************** Create Ghost-Curves Operator *********************** */
/* This operator samples the data of the selected F-Curves to F-Points, storing them
* as 'ghost curves' in the active Graph Editor
@@ -327,7 +352,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver = fcu->driver;
FPoint *fpt;
- float unitFac;
+ float unitFac, offset;
int cfra;
SpaceIpo *sipo = (SpaceIpo *) ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@@ -336,7 +361,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
fcu->driver = NULL;
/* calculate unit-mapping factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* create samples, but store them in a new curve
* - we cannot use fcurve_store_samples() as that will only overwrite the original curve
@@ -349,7 +374,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
fpt->vec[0] = cfrae;
- fpt->vec[1] = fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) * unitFac;
+ fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac;
}
/* set color of ghost curve
@@ -498,12 +523,17 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -582,7 +612,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
ListBase anim_data;
short mapping_flag = ANIM_get_normalization_flags(&ac);
-
+ float scale, offset;
/* get frame and value from props */
frame = RNA_float_get(op->ptr, "frame");
val = RNA_float_get(op->ptr, "value");
@@ -592,16 +622,18 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
/* apply inverse unit-mapping to value to get correct value for F-Curves */
- val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE);
-
+ scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
+
+ val = val * scale - offset;
+
/* insert keyframe on the specified frame + value */
insert_vert_fcurve(fcu, frame, val, 0);
-
+
ale->update |= ANIM_UPDATE_DEPS;
-
+
BLI_listbase_clear(&anim_data);
BLI_addtail(&anim_data, ale);
-
+
ANIM_animdata_update(&ac, &anim_data);
}
else {
@@ -851,13 +883,6 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- graphkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
-
void GRAPH_OT_duplicate(wmOperatorType *ot)
{
/* identifiers */
@@ -866,7 +891,6 @@ void GRAPH_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = graphkeys_duplicate_invoke;
ot->exec = graphkeys_duplicate_exec;
ot->poll = graphop_editable_keyframes_poll;
@@ -1155,6 +1179,11 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
+ if (!BLI_is_file(path)) {
+ BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
+ return OPERATOR_CANCELLED;
+ }
+
scene = ac.scene; /* current scene */
/* store necessary data for the baking steps */
@@ -1877,7 +1906,8 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
short mapping_flag = ANIM_get_normalization_flags(&ac);
KeyframeEditData current_ked;
- float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
memset(&current_ked, 0, sizeof(current_ked));
@@ -1891,7 +1921,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
ked.f1 += current_ked.f1;
ked.i1 += current_ked.i1;
- ked.f2 += current_ked.f2 * unit_scale;
+ ked.f2 += (current_ked.f2 + offset) * unit_scale;
ked.i2 += current_ked.i2;
}
@@ -1984,9 +2014,10 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* normalise cursor value (for normalised F-Curves display) */
if (mode == GRAPHKEYS_SNAP_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
- ked.f1 = cursor_value / unit_scale;
+ ked.f1 = (cursor_value / unit_scale) - offset;
}
/* perform snapping */
@@ -2111,9 +2142,10 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* apply unit corrections */
if (mode == GRAPHKEYS_MIRROR_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
- ked.f1 = cursor_value * unit_scale;
+ ked.f1 = (cursor_value + offset) * unit_scale;
}
/* perform actual mirroring */
@@ -2243,7 +2275,7 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
int index;
/* check if modifier is valid for this context */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 50412952139..a478a86a5e2 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -32,11 +32,8 @@
#define __GRAPH_INTERN_H__
struct bContext;
-struct wmWindowManager;
struct bAnimContext;
struct bAnimListElem;
-struct FCurve;
-struct FModifier;
struct SpaceIpo;
struct ScrArea;
struct ARegion;
@@ -94,6 +91,7 @@ void get_graph_keyframe_extents(struct bAnimContext *ac, float *xmin, float *xma
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
void GRAPH_OT_view_selected(struct wmOperatorType *ot);
+void GRAPH_OT_view_frame(struct wmOperatorType *ot);
void GRAPH_OT_click_insert(struct wmOperatorType *ot);
void GRAPH_OT_keyframe_insert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index da308d0b1f1..f4cce29bda8 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -87,8 +87,9 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
CFRA = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(CFRA);
SUBFRA = 0.f;
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
/* set the cursor value */
sipo->cursorVal = RNA_float_get(op->ptr, "value");
@@ -380,6 +381,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_view_all);
WM_operatortype_append(GRAPH_OT_view_selected);
WM_operatortype_append(GRAPH_OT_properties);
+ WM_operatortype_append(GRAPH_OT_view_frame);
WM_operatortype_append(GRAPH_OT_ghost_curves_create);
WM_operatortype_append(GRAPH_OT_ghost_curves_clear);
@@ -440,6 +442,7 @@ void ED_operatormacros_graph(void)
WM_operatortype_macro_define(ot, "GRAPH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
@@ -562,15 +565,14 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
/* destructive */
- WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_bake", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", DELKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
/* insertkey */
@@ -594,7 +596,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
-
+ WM_keymap_add_item(keymap, "GRAPH_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* F-Modifiers */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "only_active", false);
@@ -608,6 +611,9 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_fcurve");
+
/* pivot point settings */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 78dbae7618b..4cf8a1de7ab 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -272,7 +272,8 @@ static void borderselect_graphkeys(
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
@@ -282,8 +283,8 @@ static void borderselect_graphkeys(
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
- scaled_rectf.ymin = rectf.ymin / unit_scale;
- scaled_rectf.ymax = rectf.ymax / unit_scale;
+ scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
+ scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
@@ -1089,6 +1090,8 @@ typedef struct tNearestVertInfo {
short hpoint; /* the handle index that we hit (eHandleIndex) */
short sel; /* whether the handle is selected or not */
int dist; /* distance from mouse to vert */
+
+ eAnim_ChannelType ctype; /* type of animation channel this FCurve comes from */
} tNearestVertInfo;
/* Tags for the type of graph vert that we have */
@@ -1116,8 +1119,8 @@ static bool fcurve_handle_sel_check(SpaceIpo *sipo, BezTriple *bezt)
/* check if the given vertex is within bounds or not */
// TODO: should we return if we hit something?
static void nearest_fcurve_vert_store(
- ListBase *matches, View2D *v2d, FCurve *fcu,
- BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale)
+ ListBase *matches, View2D *v2d, FCurve *fcu, eAnim_ChannelType ctype,
+ BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale, float offset)
{
/* Keyframes or Samples? */
if (bezt) {
@@ -1129,7 +1132,7 @@ static void nearest_fcurve_vert_store(
* 'vec' matrix
*/
if (UI_view2d_view_to_region_clip(v2d,
- bezt->vec[hpoint + 1][0], bezt->vec[hpoint + 1][1] * unit_scale,
+ bezt->vec[hpoint + 1][0], (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
&screen_co[0], &screen_co[1]) &&
/* check if distance from mouse cursor to vert in screen space is within tolerance */
((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
@@ -1149,6 +1152,8 @@ static void nearest_fcurve_vert_store(
/* store values */
nvi->fcu = fcu;
+ nvi->ctype = ctype;
+
nvi->bezt = bezt;
nvi->hpoint = hpoint;
nvi->dist = dist;
@@ -1189,30 +1194,31 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
-
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+
/* apply NLA mapping to all the keyframes */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
-
+
if (fcu->bezt) {
BezTriple *bezt1 = fcu->bezt, *prevbezt = NULL;
int i;
for (i = 0; i < fcu->totvert; i++, prevbezt = bezt1, bezt1++) {
/* keyframe */
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale, offset);
/* handles - only do them if they're visible */
if (fcurve_handle_sel_check(sipo, bezt1) && (fcu->totvert > 1)) {
/* first handle only visible if previous segment had handles */
if ((!prevbezt && (bezt1->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale, offset);
}
/* second handle only visible if this segment is bezier */
if (bezt1->ipo == BEZT_IPO_BEZ) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale, offset);
}
}
}
@@ -1405,7 +1411,7 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
/* needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY) otherwise the active flag won't be set [#26452] */
if (nvi->fcu->flag & FCURVE_SELECTED) {
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
/* free temp sample data for filtering */
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index eea360ced45..0e56dc817e4 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -210,13 +210,18 @@ int graphop_active_fcurve_poll(bContext *C)
if (ale == NULL)
return 0;
- /* free temp data... */
- has_fcurve = ((ale->data) && (ale->type == ANIMTYPE_FCURVE));
+ /* do we have a suitable F-Curves?
+ * - For most cases, NLA Control Curves are sufficiently similar to NLA curves to serve this role too.
+ * Under the hood, they are F-Curves too. The only problems which will arise here are if these need to be
+ * in an Action too (but drivers would then also be affected!)
+ */
+ has_fcurve = ((ale->data) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE));
if (has_fcurve) {
FCurve *fcu = (FCurve *)ale->data;
has_fcurve = (fcu->flag & FCURVE_VISIBLE) != 0;
}
+ /* free temp data... */
MEM_freeN(ale);
/* return success */
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index fb3c140fddf..fac9369928b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -44,6 +44,7 @@
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "BKE_scene.h"
#include "RE_pipeline.h"
@@ -82,9 +83,9 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
else {
if (ima->source == IMA_SRC_MOVIE) {
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs);
- if (ima->anim)
+ if (BKE_image_has_anim(ima))
ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"),
- IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN));
}
else {
ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs);
@@ -311,10 +312,11 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
- if (rr->rectf) {
+ RenderView *rv = RE_RenderViewGetById(rr, 0);
+ if (rv->rectf) {
return IFACE_("Composite");
}
- else if (rr->rect32) {
+ else if (rv->rect32) {
return IFACE_("Sequence");
}
else {
@@ -358,7 +360,7 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void
for (rl = rr->layers.last; rl; rl = rl->prev, nr--) {
final:
- uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rl->name), 0, 0,
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, rl->name, 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->layer, (float) nr, 0.0, 0, -1, "");
}
@@ -375,7 +377,7 @@ final:
static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
{
- if (rl == NULL || rl->rectf) {
+ if (rl == NULL) {
return IFACE_("Combined");
}
else {
@@ -383,9 +385,9 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
}
}
-static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *ptrpair_p)
+static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = ptrpair_p;
+ void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
@@ -398,6 +400,7 @@ 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);
@@ -419,15 +422,22 @@ 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.name, fake_name, sizeof(rpass_fake.name));
+ BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
nr += 1;
}
/* rendered results don't have a Combined pass */
for (rpass = rl ? rl->passes.last : NULL; rpass; rpass = rpass->prev, nr--) {
+
+ /* just show one pass of each kind */
+ if (passflag & rpass->passtype)
+ continue;
+
+ passflag |= rpass->passtype;
+
final:
- 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, "");
+ uiDefButI(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->passtype, (float) rpass->passtype, 0.0, 0, -1, "");
}
if (fake_name) {
@@ -441,21 +451,81 @@ final:
BKE_image_release_renderresult(scene, image);
}
+/**************************** view menus *****************************/
+static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ RenderResult *rr;
+ RenderView *rview;
+ int nr;
+ Scene *scene = iuser->scene;
+
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1;
+ for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rview->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
+
+ BKE_image_release_renderresult(scene, image);
+}
+
+static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ int nr;
+ ImageView *iv;
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = BLI_listbase_count(&image->views) - 1;
+ for (iv = image->views.last; iv; iv = iv->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(iv->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
+}
+
/* 5 layer button callbacks... */
static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
{
ImageUser *iuser = iuser_v;
- BKE_image_multilayer_index(rr_v, iuser);
+ BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
+
static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
int tot = BLI_listbase_count(&rr->layers);
- if (rr->rectf || rr->rect32)
+ if (RE_HasFakeLayer(rr))
tot++; /* fake compo/sequencer layer */
if (iuser->layer < tot - 1) {
@@ -478,32 +548,75 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
- RenderLayer *rl = BLI_findlink(&rr->layers, iuser->layer);
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderPass *next = NULL;
+ int layer = iuser->layer;
- if (rl) {
- int tot = BLI_listbase_count(&rl->passes);
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
- if (rr->rectf || rr->rect32)
- tot++; /* fake compo/sequencer layer */
+ rl = BLI_findlink(&rr->layers, layer);
- if (iuser->pass < tot - 1) {
- iuser->pass++;
- BKE_image_multilayer_index(rr, iuser);
+ if (rl) {
+ for (rp = rl->passes.first; rp; rp = rp->next) {
+ if (rp->passtype == iuser->passtype) {
+ next = rp->next;
+ if (next != NULL && next->passtype == rp->passtype)
+ next = next->next;
+ break;
+ }
+ }
+
+ if (next != NULL && iuser->passtype != next->passtype) {
+ iuser->passtype = next->passtype;
+ BKE_image_multilayer_index(rr, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
}
}
static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
+ RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderPass *prev = NULL;
+ int layer = iuser->layer;
- if (iuser->pass > 0) {
- iuser->pass--;
- BKE_image_multilayer_index(rr_v, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
+
+ rl = BLI_findlink(&rr->layers, layer);
+
+ if (rl) {
+ for (rp = rl->passes.last; rp; rp = rp->prev) {
+ if (rp->passtype == iuser->passtype) {
+ prev = rp->prev;
+ if (prev != NULL && prev->passtype == rp->passtype)
+ prev = prev->prev;
+ break;
+ }
+ }
+
+ if (prev != NULL && iuser->passtype != prev->passtype) {
+ iuser->passtype = prev->passtype;
+ BKE_image_multilayer_index(rr, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ }
}
}
+/* 5 view button callbacks... */
+static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
+{
+ Image *ima = ima_v;
+ ImageUser *iuser = iuser_v;
+
+ BKE_image_multiview_index(ima, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+}
+
#if 0
static void image_freecache_cb(bContext *C, void *ima_v, void *unused)
{
@@ -523,13 +636,14 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
{
- static void *rnd_pt[3]; /* XXX, workaround */
+ static void *rnd_pt[4]; /* XXX, workaround */
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
- int wmenu1, wmenu2, wmenu3;
+ int wmenu1, wmenu2, wmenu3, wmenu4;
const char *fake_name;
- const char *display_name;
+ const char *display_name = "";
+ const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO);
uiLayoutRow(layout, true);
@@ -537,6 +651,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
wmenu1 = (2 * w) / 5;
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
+ wmenu4 = (3 * w) / 6;
rnd_pt[0] = image;
rnd_pt[1] = iuser;
@@ -558,6 +673,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
if (rr) {
RenderPass *rpass;
+ RenderView *rview;
int rpass_index;
/* layer */
@@ -566,29 +682,61 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
rl = BLI_findlink(&rr->layers, rpass_index);
rnd_pt[2] = SET_INT_IN_POINTER(rpass_index);
- display_name = rl ? rl->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name, 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
- UI_but_func_set(but, image_multi_cb, rr, iuser);
- UI_but_type_set_menu_from_pulldown(but);
-
+ if (RE_layers_have_name(rr)) {
+ display_name = rl ? rl->name : (fake_name ? fake_name : "");
+ but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name,
+ 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
/* pass */
fake_name = ui_imageuser_pass_fake_name(rl);
- rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
+ rpass = (rl ? RE_pass_find_by_type(rl, iuser->passtype, ((RenderView *)rr->views.first)->name) : NULL);
- display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, display_name, 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
+ display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
+ but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
+ 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
+
+ /* view */
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1 && !show_stereo) {
+ rview = BLI_findlink(&rr->views, iuser->view);
+ display_name = rview ? rview->name : "";
+
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
+ }
+
+ /* stereo image */
+ else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
+ ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
+ {
+ ImageView *iv;
+ int nr = 0;
+
+ for (iv = image->views.first; iv; iv = iv->next) {
+ if (nr++ == iuser->view) {
+ display_name = iv->name;
+ break;
+ }
+ }
+
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_func_set(but, image_multiview_cb, image, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
}
}
-static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, short *render_slot)
+static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser,
+ int menus_width, short *render_slot)
{
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row;
uiBut *but;
- const float dpi_fac = UI_DPI_FAC;
row = uiLayoutRow(layout, true);
@@ -605,7 +753,7 @@ static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, Ren
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
UI_but_func_set(but, image_multi_inclay_cb, rr, iuser);
- uiblock_layer_pass_buttons(row, image, rr, iuser, 230 * dpi_fac, render_slot);
+ uiblock_layer_pass_buttons(row, image, rr, iuser, menus_width, render_slot);
/* decrease, increase arrows */
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
@@ -639,7 +787,7 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
RNA_property_update(C, &cb->ptr, cb->prop);
}
-void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
+void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact, int multiview)
{
PropertyRNA *prop;
PointerRNA imaptr;
@@ -722,10 +870,17 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
else if (ima->type == IMA_TYPE_R_RESULT) {
/* browse layer/passes */
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 230 * dpi_fac;
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, &ima->render_slot);
+ if (rr) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
@@ -734,13 +889,13 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (ima->source != IMA_SRC_GENERATED) {
row = uiLayoutRow(layout, true);
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -758,7 +913,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* multilayer? */
if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
- uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, NULL);
+ const float dpi_fac = UI_DPI_FAC;
+ uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
@@ -784,6 +940,16 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
BKE_image_release_ibuf(ima, ibuf, NULL);
}
+ if (multiview) {
+ if ((scene->r.scemode & R_MULTIVIEW) != 0) {
+ uiItemR(layout, &imaptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(&imaptr, "use_multiview")) {
+ uiTemplateImageViews(layout, &imaptr);
+ }
+ }
+ }
+
if (has_alpha) {
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE);
@@ -797,8 +963,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
}
- uiItemS(layout);
-
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
@@ -962,18 +1126,118 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
}
}
+void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
+{
+ Stereo3dFormat *stereo3d_format = stereo3d_format_ptr->data;
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
+
+ switch (stereo3d_format->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ {
+ uiItemR(col, stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_INTERLACE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
+ uiItemR(col, stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
+ /* fall-through */
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_squeezed_frame", 0, NULL, ICON_NONE);
+ break;
+ }
+ }
+}
+
+static void uiTemplateViewsFormat(uiLayout *layout, PointerRNA *ptr, PointerRNA *stereo3d_format_ptr)
+{
+ uiLayout *col, *box;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Views Format:"), ICON_NONE);
+ uiItemR(uiLayoutRow(col, false), ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ if (stereo3d_format_ptr) {
+ box = uiLayoutBox(col);
+ uiLayoutSetActive(box, RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D);
+ uiTemplateImageStereo3d(box, stereo3d_format_ptr);
+ }
+}
+
+void uiTemplateImageViews(uiLayout *layout, PointerRNA *imaptr)
+{
+ Image *ima = imaptr->data;
+
+ if (ima->type != IMA_TYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imaptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imaptr, prop);
+
+ uiTemplateViewsFormat(layout, imaptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imaptr, NULL);
+ }
+}
+
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
+{
+ ImageFormatData *imf = imfptr->data;
+
+ if (ptr == NULL)
+ return;
+
+ uiItemR(layout, ptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(ptr, "use_multiview")) {
+ if (imf->imtype != R_IMF_IMTYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imfptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imfptr, prop);
+
+ uiTemplateViewsFormat(layout, imfptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imfptr, NULL);
+ }
+ }
+}
+
void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
{
Scene *scene = CTX_data_scene(C);
/* render layers and passes */
if (ima && iuser) {
- const float dpi_fac = UI_DPI_FAC;
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 160 * dpi_fac;
+ const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT);
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_buttons(layout, ima, rr, iuser, 160 * dpi_fac, (ima->type == IMA_TYPE_R_RESULT) ? &ima->render_slot : NULL);
+ if (rr && is_render_result) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width,
+ is_render_result ? &ima->render_slot : NULL);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index d03f3c157a9..36419ccd10d 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -106,9 +106,10 @@ static void draw_render_info(const bContext *C,
if (re) {
int total_tiles;
+ bool need_free_tiles;
rcti *tiles;
- RE_engine_get_current_tiles(re, &total_tiles, &tiles);
+ tiles = RE_engine_get_current_tiles(re, &total_tiles, &need_free_tiles);
if (total_tiles) {
int i, x, y;
@@ -133,7 +134,9 @@ static void draw_render_info(const bContext *C,
glaDrawBorderCorners(tile, zoomx, zoomy);
}
- MEM_freeN(tiles);
+ if (need_free_tiles) {
+ MEM_freeN(tiles);
+ }
glPopMatrix();
}
@@ -780,7 +783,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
Image *ima;
ImBuf *ibuf;
float zoomx, zoomy;
- bool show_viewer, show_render, show_paint;
+ bool show_viewer, show_render, show_paint, show_stereo3d, show_multilayer;
void *lock;
/* XXX can we do this in refresh? */
@@ -810,6 +813,8 @@ void draw_image_main(const bContext *C, ARegion *ar)
show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
+ show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
+ show_multilayer = ima && BKE_image_is_multilayer(ima);
if (show_viewer) {
/* use locked draw for drawing viewer image buffer since the compositor
@@ -820,17 +825,41 @@ void draw_image_main(const bContext *C, ARegion *ar)
BLI_lock_thread(LOCK_DRAW_IMAGE);
}
+ if (show_stereo3d) {
+ if (show_multilayer)
+ /* update multiindex and pass for the current eye */
+ BKE_image_multilayer_index(ima->rr, &sima->iuser);
+ else
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* draw the image or grid */
- if (ibuf == NULL)
+ if (ibuf == NULL) {
ED_region_grid_draw(ar, zoomx, zoomy);
- else if (sima->flag & SI_DRAW_TILE)
- draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
- else if (ima && (ima->tpageflag & IMA_TILES))
- draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
- else
- draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+ }
+ else {
+
+ if (sima->flag & SI_DRAW_TILE)
+ draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
+ else if (ima && (ima->tpageflag & IMA_TILES))
+ draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
+ else
+ draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+
+ if (sima->flag & SI_DRAW_METADATA) {
+ int x, y;
+ rctf frame;
+
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
+
+ ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx, zoomy);
+ }
+ }
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
/* paint helpers */
if (show_paint)
@@ -853,8 +882,6 @@ void draw_image_main(const bContext *C, ARegion *ar)
}
#endif
- ED_space_image_release_buffer(sima, ibuf, lock);
-
if (show_viewer) {
BLI_unlock_thread(LOCK_DRAW_IMAGE);
}
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 8e2c6b97a5b..38c9604d14b 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -104,7 +104,7 @@ void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
}
}
-ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
+ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
{
ImBuf *ibuf;
@@ -114,7 +114,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
return BIF_render_spare_imbuf();
else
#endif
- ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r);
+ ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
if (ibuf) {
if (ibuf->rect || ibuf->rect_float)
@@ -124,7 +124,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
}
}
else
- *lock_r = NULL;
+ *r_lock = NULL;
return NULL;
}
@@ -299,7 +299,7 @@ void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *s
/* scope update can be expensive, don't update during paint modes */
if (sima->mode == SI_MODE_PAINT)
return;
- if (ob && ((ob->mode & OB_MODE_TEXTURE_PAINT) != 0))
+ if (ob && ((ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0))
return;
scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings);
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index aecc43f4fdf..6eaad302180 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -38,11 +38,7 @@ struct ARegion;
struct ARegionType;
struct ScrArea;
struct SpaceImage;
-struct Object;
-struct Image;
-struct ImBuf;
struct wmOperatorType;
-struct Scene;
struct bNodeTree;
/* space_image.c */
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 61667b02140..72e3f21b1be 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -30,14 +30,21 @@
#include <stddef.h>
#include <string.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
#include "BLF_translation.h"
@@ -60,6 +67,7 @@
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "GPU_draw.h"
#include "GPU_buffers.h"
@@ -68,6 +76,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
+#include "intern/openexr/openexr_multi.h"
#include "RE_pipeline.h"
@@ -76,6 +85,7 @@
#include "RNA_enum_types.h"
#include "ED_image.h"
+#include "ED_mask.h"
#include "ED_paint.h"
#include "ED_render.h"
#include "ED_screen.h"
@@ -369,7 +379,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -585,7 +595,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -711,6 +721,9 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
ot->exec = image_view_all_exec;
ot->poll = space_image_main_area_poll;
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -742,8 +755,15 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
height = height * aspy;
/* get bounds */
- if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
- return OPERATOR_CANCELLED;
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
+ return OPERATOR_CANCELLED;
+ }
+ else if (ED_space_image_check_show_maskedit(scene, sima)) {
+ if (!ED_mask_selected_minmax(C, min, max)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
/* adjust offset and zoom */
sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width);
@@ -763,7 +783,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static int image_view_selected_poll(bContext *C)
{
- return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
+ return (space_image_main_area_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -936,6 +956,7 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path)
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
ImageUser *iuser;
+ ImageFormatData im_format;
} ImageOpenData;
typedef struct ImageFrame {
@@ -946,7 +967,6 @@ typedef struct ImageFrame {
static void image_open_init(bContext *C, wmOperator *op)
{
ImageOpenData *iod;
-
op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
@@ -996,6 +1016,7 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
}
else {
/* different file base name found, is ignored */
+ MEM_freeN(filename);
MEM_freeN(frame);
break;
}
@@ -1048,7 +1069,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
- ImageOpenData *iod;
+ ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
char path[FILE_MAX];
@@ -1060,15 +1081,27 @@ static int image_open_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
- if (!IMB_isanim(path) && RNA_struct_property_is_set(op->ptr, "files") &&
- RNA_struct_property_is_set(op->ptr, "directory"))
+ if (RNA_struct_property_is_set(op->ptr, "directory") &&
+ RNA_struct_property_is_set(op->ptr, "files"))
{
- ListBase frames;
-
- BLI_listbase_clear(&frames);
- image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
- frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
- BLI_freelistN(&frames);
+ /* only to pass to imbuf */
+ char path_full[FILE_MAX];
+ BLI_strncpy(path_full, path, sizeof(path_full));
+ BLI_path_abs(path_full, G.main->name);
+
+ if (!IMB_isanim(path_full)) {
+ bool was_relative = BLI_path_is_rel(path);
+ ListBase frames;
+
+ BLI_listbase_clear(&frames);
+ image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
+ frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
+ BLI_freelistN(&frames);
+
+ if (was_relative) {
+ BLI_path_rel(path, G.main->name);
+ }
+ }
}
errno = 0;
@@ -1085,6 +1118,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (!op->customdata)
image_open_init(C, op);
+ /* handle multiview images */
+ if (RNA_boolean_get(op->ptr, "use_multiview")) {
+ ImageFormatData *imf = &iod->im_format;
+
+ ima->flag |= IMA_USE_VIEWS;
+ ima->views_format = imf->views_format;
+ *ima->stereo3d_format = imf->stereo3d_format;
+ }
+ else {
+ ima->flag &= ~IMA_USE_VIEWS;
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+
/* only image path after save, never ibuf */
if (is_relative_path) {
if (!exists) {
@@ -1128,6 +1176,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->framenr = 1;
iuser->offset = frame_ofs - 1;
iuser->fie_ima = 2;
+ iuser->scene = scene;
+ BKE_image_init_imageuser(ima, iuser);
}
/* XXX unpackImage frees image buffers */
@@ -1146,7 +1196,8 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
const char *path = U.textudir;
Image *ima = NULL;
-
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
if (sima) {
ima = sima->image;
}
@@ -1185,11 +1236,44 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
image_filesel(C, op, path);
return OPERATOR_RUNNING_MODAL;
}
+static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
+static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ ImageOpenData *iod = op->customdata;
+ ImageFormatData *imf = &iod->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
+
/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
@@ -1202,6 +1286,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->exec = image_open_exec;
ot->invoke = image_open_invoke;
ot->cancel = image_open_cancel;
+ ot->ui = image_open_draw;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1233,10 +1318,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
}
- if (!ima || !iuser || !ima->anim)
+ if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
- iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
+ iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
return OPERATOR_FINISHED;
@@ -1285,7 +1370,7 @@ static int image_replace_exec(bContext *C, wmOperator *op)
/* XXX unpackImage frees image buffers */
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- BKE_icon_changed(BKE_icon_getid(&sima->image->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
@@ -1433,6 +1518,10 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@@ -1468,30 +1557,104 @@ static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
RNA_string_set(op->ptr, "filepath", simopts->filepath);
}
+static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
+{
+ if (ok) {
+ if (!save_copy) {
+ ColorManagedColorspaceSettings old_colorspace_settings;
+
+ if (do_newpath) {
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
+ BLI_strncpy(ima->name, filepath, sizeof(ima->name));
+ }
+
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ /* change type? */
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ ima->type = IMA_TYPE_IMAGE;
+
+ /* workaround to ensure the render result buffer is no longer used
+ * by this image, otherwise can crash when a new render result is
+ * created. */
+ if (ibuf->rect && !(ibuf->mall & IB_rect))
+ imb_freerectImBuf(ibuf);
+ if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
+ imb_freerectfloatImBuf(ibuf);
+ if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
+ IMB_freezbufImBuf(ibuf);
+ if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+
+ /* only image path, never ibuf */
+ if (relative) {
+ BLI_path_rel(ima->name, relbase); /* only after saving */
+ }
+
+ BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings,
+ &ima->colorspace_settings);
+ IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
+ &ima->colorspace_settings))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ }
+ }
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
+ }
+}
+
+static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* This guys might be modified by image buffer write functions,
+ * need to copy them back from color managed image buffer to an
+ * original one, so file type of image is being properly updated.
+ */
+ ibuf->ftype = colormanaged_ibuf->ftype;
+ ibuf->planes = colormanaged_ibuf->planes;
+
+ IMB_freeImBuf(colormanaged_ibuf);
+ }
+}
+
/**
* \return success.
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
+ * \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
{
Image *ima = ED_space_image(sima);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ Scene *scene;
+ RenderResult *rr = NULL;
bool ok = false;
+ WM_cursor_wait(1);
+
if (ibuf) {
- ImBuf *colormanaged_ibuf;
+ ImBuf *colormanaged_ibuf = NULL;
const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
ImageFormatData *imf = &simopts->im_format;
+ const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER;
+ bool is_mono;
+
/* old global to ensure a 2nd save goes to same dir */
BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
- WM_cursor_wait(1);
-
if (ima->type == IMA_TYPE_R_RESULT) {
/* enforce user setting for RGB or RGBA, but skip BW */
if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
@@ -1512,83 +1675,194 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
}
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ /* we need renderresult for exr and rendered multiview */
+ scene = CTX_data_scene(C);
+ rr = BKE_image_acquire_renderresult(scene, ima);
+ is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
- if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- Scene *scene = CTX_data_scene(C);
- RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
- if (rr) {
- ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.exr_codec);
- }
- else {
+ /* error handling */
+ if (!rr) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
+ goto cleanup;
}
- BKE_image_release_renderresult(scene, ima);
}
else {
- ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy);
- }
-
- if (ok) {
- if (!save_copy) {
- if (do_newpath) {
- BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name));
+ if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if ((ima->flag & IMA_IS_STEREO) == 0) {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
- ibuf->userflags &= ~IB_BITMAPDIRTY;
-
- /* change type? */
- if (ima->type == IMA_TYPE_R_RESULT) {
- ima->type = IMA_TYPE_IMAGE;
-
- /* workaround to ensure the render result buffer is no longer used
- * by this image, otherwise can crash when a new render result is
- * created. */
- if (ibuf->rect && !(ibuf->mall & IB_rect))
- imb_freerectImBuf(ibuf);
- if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
- imb_freerectfloatImBuf(ibuf);
- if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
- IMB_freezbufImBuf(ibuf);
- if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
- IMB_freezbuffloatImBuf(ibuf);
- }
- if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
+ /* it shouldn't ever happen*/
+ if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
+ (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
+ {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
+ }
+ BKE_imbuf_stamp_info(rr, ibuf);
+ }
+
+ /* fancy multiview OpenEXR */
+ if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ /* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */
+ BKE_imbuf_write_prepare(ibuf, imf);
+ ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview));
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* regular mono pipeline */
+ else if (is_mono) {
+ if (is_multilayer) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ }
+ 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);
+ }
+ save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* individual multiview images */
+ else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t i;
+ unsigned char planes = ibuf->planes;
+ const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
+
+ if (!is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
- /* only image path, never ibuf */
- if (relative) {
- BLI_path_rel(ima->name, relbase); /* only after saving */
+ for (i = 0; i < totviews; i++) {
+ char filepath[FILE_MAX];
+ bool ok_view = false;
+ const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
+ ((ImageView *) BLI_findlink(&ima->views, i))->name;
+
+ if (is_multilayer) {
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+ ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ }
+ else {
+ /* copy iuser to get the correct ibuf for this view */
+ ImageUser iuser = sima->iuser;
+ iuser.view = i;
+ iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr)
+ BKE_image_multilayer_index(rr, &iuser);
+ else
+ BKE_image_multiview_index(ima, &iuser);
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+ ibuf->planes = planes;
+
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
}
+ ok &= ok_view;
+ }
- IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
}
- else {
- BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", simopts->filepath);
- }
+ /* stereo (multiview) images */
+ else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else {
+ ImBuf *ibuf_stereo[2] = {NULL};
+ unsigned char planes = ibuf->planes;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+ /* we need to get the specific per-view buffers */
+ ED_space_image_release_buffer(sima, ibuf, lock);
- WM_cursor_wait(0);
+ for (i = 0; i < 2; i ++) {
+ ImageUser iuser = sima->iuser;
+ iuser.flag &= ~IMA_SHOW_STEREO;
- if (colormanaged_ibuf != ibuf) {
- /* This guys might be modified by image buffer write functions,
- * need to copy them back from color managed image buffer to an
- * original one, so file type of image is being properly updated.
- */
- ibuf->ftype = colormanaged_ibuf->ftype;
- ibuf->planes = colormanaged_ibuf->planes;
+ if (rr) {
+ int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ iuser.view = id;
+ BKE_image_multilayer_index(rr, &iuser);
+ }
+ else {
+ iuser.view = i;
+ BKE_image_multiview_index(ima, &iuser);
+ }
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+
+ if (ibuf == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
+ goto cleanup;
+ }
- IMB_freeImBuf(colormanaged_ibuf);
+ ibuf->planes = planes;
+
+ /* color manage the ImBuf leaving it ready for saving */
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
+ &imf->view_settings, &imf->display_settings, imf);
+
+ BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
+ IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
+
+ /* duplicate buffer to prevent locker issue when using render result */
+ ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
+
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
+ }
+
+ ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
+
+ /* save via traditional path */
+ ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
+
+ IMB_freeImBuf(ibuf);
+
+ for (i = 0; i < 2; i ++) {
+ IMB_freeImBuf(ibuf_stereo[i]);
+ }
+ }
}
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+
+ }
+ else {
+cleanup:
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
- ED_space_image_release_buffer(sima, ibuf, lock);
+ if (rr) {
+ BKE_image_release_renderresult(scene, ima);
+ }
+
+ WM_cursor_wait(0);
return ok;
}
@@ -1636,6 +1910,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
Image *ima = ED_space_image(sima);
Scene *scene = CTX_data_scene(C);
SaveImageOptions simopts;
+ PropertyRNA *prop;
const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
if (RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -1657,6 +1932,12 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
+ /* show multiview save options only if image has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+ prop = RNA_struct_find_property(op->ptr, "use_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+
image_filesel(C, op, simopts.filepath);
return OPERATOR_RUNNING_MODAL;
@@ -1683,15 +1964,20 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ImageFormatData *imf = op->customdata;
- PointerRNA ptr;
+ PointerRNA imf_ptr, ptr;
+ const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
/* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
- uiTemplateImageSettings(layout, &ptr, false);
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
+
+ /* multiview template */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
static int image_save_as_poll(bContext *C)
@@ -1714,8 +2000,6 @@ static int image_save_as_poll(bContext *C)
void IMAGE_OT_save_as(wmOperatorType *ot)
{
-// PropertyRNA *prop;
-
/* identifiers */
ot->name = "Save As Image";
ot->idname = "IMAGE_OT_save_as";
@@ -1932,6 +2216,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
float color[4];
int width, height, floatbuf, gen_type, alpha;
int gen_context;
+ int stereo3d;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -1952,11 +2237,12 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
gen_context = RNA_enum_get(op->ptr, "gen_context");
+ stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
if (!alpha)
color[3] = 1.0f;
- ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color);
+ ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
if (!ima)
return OPERATOR_CANCELLED;
@@ -2036,6 +2322,53 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
+static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *split, *col[2];
+ uiLayout *layout = op->layout;
+ PointerRNA ptr;
+#if 0
+ Scene *scene = CTX_data_scene(C);
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+#endif
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ /* copy of WM_operator_props_dialog_popup() layout */
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Name"), ICON_NONE);
+ uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Width"), ICON_NONE);
+ uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Height"), ICON_NONE);
+ uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Color"), ICON_NONE);
+ uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
+ uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
+
+#if 0
+ if (is_multiview) {
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
+ }
+#endif
+}
+
void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2056,6 +2389,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_new_exec;
ot->invoke = image_new_invoke;
+ ot->ui = image_new_draw;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -2075,7 +2409,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
RNA_def_property_flag(prop, PROP_HIDDEN);
-
+ prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
#undef IMA_DEF_NAME
@@ -2103,7 +2438,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
const bool b = RNA_boolean_get(op->ptr, "invert_b");
const bool a = RNA_boolean_get(op->ptr, "invert_a");
- int i;
+ size_t i;
if (ibuf == NULL) /* TODO: this should actually never happen, but does for render-results -> cleanup */
return OPERATOR_CANCELLED;
@@ -2114,13 +2449,13 @@ static int image_invert_exec(bContext *C, wmOperator *op)
/* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
* but better do this right in case someone copies this for a tool that uses partial redraw better */
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
float *fp = (float *) ibuf->rect_float;
- for (i = ibuf->x * ibuf->y; i > 0; i--, fp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
if (r) fp[0] = 1.0f - fp[0];
if (g) fp[1] = 1.0f - fp[1];
if (b) fp[2] = 1.0f - fp[2];
@@ -2134,7 +2469,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
else if (ibuf->rect) {
char *cp = (char *) ibuf->rect;
- for (i = ibuf->x * ibuf->y; i > 0; i--, cp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
if (r) cp[0] = 255 - cp[0];
if (g) cp[1] = 255 - cp[1];
if (b) cp[2] = 255 - cp[2];
@@ -2200,7 +2535,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
if (!ima)
return 0;
- if (!as_png && ima->packedfile)
+ if (!as_png && BKE_image_has_packedfile(ima))
return 0;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2229,7 +2564,7 @@ static int image_pack_exec(bContext *C, wmOperator *op)
if (as_png)
BKE_image_memorypack(ima);
else
- ima->packedfile = newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -2301,7 +2636,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
if (!ima) ima = CTX_data_edit_image(C);
}
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2329,7 +2664,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (RNA_struct_property_is_set(op->ptr, "id"))
return image_unpack_exec(C, op);
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2340,7 +2675,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (G.fileflags & G_AUTOPACK)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
- unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", ima->packedfile);
+ unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
return OPERATOR_FINISHED;
}
@@ -2609,8 +2944,11 @@ static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- image_sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ image_sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
image_sample_apply(C, op, event);
break;
@@ -2982,7 +3320,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index bd3d76bbaba..a9a5e601e10 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -156,7 +156,9 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
simage->iuser.ok = true;
simage->iuser.fie_ima = 2;
simage->iuser.frames = 100;
-
+ simage->iuser.flag = IMA_SHOW_STEREO;
+ simage->iuser.passtype = SCE_PASS_COMBINED;
+
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
@@ -681,7 +683,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
float col[3];
-
+
/* XXX not supported yet, disabling for now */
scene->r.scemode &= ~R_COMP_CROP;
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index e2895109b48..cd424f45842 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -50,7 +50,7 @@
#include "UI_view2d.h"
#include "info_intern.h"
-#include "../space_info/textview.h"
+#include "textview.h"
/* complicates things a bit, so leaving in old simple code */
#define USE_INFO_NEWLINE
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 240d8baa6f2..a1f90f16bbf 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -134,7 +134,7 @@ static int autopack_toggle_exec(bContext *C, wmOperator *op)
G.fileflags &= ~G_AUTOPACK;
}
else {
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
}
@@ -161,7 +161,7 @@ static int pack_all_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index a0dfb285a1c..48a39cd79fc 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -56,6 +56,8 @@
#include "ED_info.h"
#include "ED_armature.h"
+#include "GPU_extensions.h"
+
#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
@@ -381,6 +383,7 @@ static void stats_string(Scene *scene)
Object *ob = (scene->basact) ? scene->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
+ char gpumemstr[MAX_INFO_MEM_LEN] = "";
char *s;
size_t ofs = 0;
@@ -416,11 +419,22 @@ static void stats_string(Scene *scene)
/* get memory statistics */
- s = memstr;
- ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem:%.2fM"),
(double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+ BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem:%.2fM"), (double)((gpu_free_mem)) / 1024.0);
+
+ if (gpu_tot_memory) {
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%.2fM"), (double)((gpu_tot_memory)) / 1024.0);
+ }
+ }
s = stats->infostr;
ofs = 0;
@@ -447,22 +461,23 @@ static void stats_string(Scene *scene)
}
ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s"),
- stats_fmt.totbonesel, stats_fmt.totbone, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
+ stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s"), stats_fmt.totvert,
- stats_fmt.tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
+ stats_fmt.tottri, gpumemstr);
}
else {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s"),
+ IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s%s"),
stats_fmt.totvert, stats_fmt.totface,
stats_fmt.tottri, stats_fmt.totobjsel,
stats_fmt.totobj, stats_fmt.totlampsel,
- stats_fmt.totlamp, memstr);
+ stats_fmt.totlamp, memstr, gpumemstr);
}
if (ob)
diff --git a/source/blender/editors/space_logic/logic_intern.h b/source/blender/editors/space_logic/logic_intern.h
index 38b122f64b6..13146621d1b 100644
--- a/source/blender/editors/space_logic/logic_intern.h
+++ b/source/blender/editors/space_logic/logic_intern.h
@@ -35,12 +35,8 @@
/* internal exports only */
struct bContext;
struct ARegion;
-struct ARegionType;
struct ScrArea;
-struct SpaceLogic;
-struct Object;
struct wmOperatorType;
-struct Scene;
/* space_logic.c */
struct ARegion *logic_has_buttons_region(struct ScrArea *sa);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 7204144ce85..e78100f3ceb 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -903,7 +903,7 @@ static void draw_sensor_internal_header(uiLayout *layout, PointerRNA *ptr)
sub = uiLayoutRow(row, false);
uiLayoutSetActive(sub, (RNA_boolean_get(ptr, "use_pulse_true_level") ||
RNA_boolean_get(ptr, "use_pulse_false_level")));
- uiItemR(sub, ptr, "frequency", 0, IFACE_("Freq"), ICON_NONE);
+ uiItemR(sub, ptr, "tick_skip", 0, IFACE_("Skip"), ICON_NONE);
row = uiLayoutRow(split, true);
uiItemR(row, ptr, "use_level", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 66023ce1243..1fb7228dd98 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -159,7 +159,9 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
}
/* AnimData pointer */
- RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ if (adt_ptr) {
+ RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ }
/* set found status to -1, since setting to 1 would break the loop
* and potentially skip an active NLA-Track in some cases...
@@ -282,7 +284,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row = uiLayoutRow(layout, true);
- uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/); // XXX: need to make these operators
+ uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink");
/* extrapolation */
row = uiLayoutRow(layout, true);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 5476d1c2683..32a8e660f66 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -291,10 +291,12 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
* the case of users trying to use this to change actions
* - in tweakmode, clicking here gets us out of tweakmode, as changing selection
* while in tweakmode is really evil!
+ * - we disable "solo" flags too, to make it easier to work with stashed actions
+ * with less trouble
*/
if (nlaedit_is_tweakmode_on(ac)) {
/* exit tweakmode immediately */
- nlaedit_disable_tweakmode(ac);
+ nlaedit_disable_tweakmode(ac, true);
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
@@ -504,6 +506,52 @@ void NLA_OT_action_pushdown(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
+/* ******************** Action Unlink ******************************** */
+
+static int nla_action_unlink_poll(bContext *C)
+{
+ if (ED_operator_nla_active(C)) {
+ return nla_panel_context(C, NULL, NULL, NULL);
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int nla_action_unlink_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA adt_ptr;
+ AnimData *adt;
+
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
+ return OPERATOR_CANCELLED;
+
+ /* get animdata */
+ adt = adt_ptr.data;
+ if (adt == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* do unlinking */
+ if (adt && adt->action) {
+ ED_animedit_unlink_action(C, adt_ptr.id.data, adt, adt->action, op->reports);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void NLA_OT_action_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "NLA_OT_action_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->exec = nla_action_unlink_exec;
+ ot->poll = nla_action_unlink_poll;
+}
+
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
@@ -725,7 +773,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* ensure that object has AnimData... that's all */
- BKE_id_add_animdata(&ob->id);
+ BKE_animdata_add_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index aae0e38696c..4d37fcc9276 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -186,7 +186,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
else {
/* Action Clip (default/normal type of strip) */
- if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
+ if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
/* active strip should be drawn green when it is acting as the tweaking strip.
* however, this case should be skipped for when not in EditMode...
*/
@@ -433,7 +433,7 @@ static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, i
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -490,11 +490,11 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
* while also preserving some accuracy, since we do use floats
*/
/* start frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->start);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
/* end frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->end);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
}
@@ -650,6 +650,8 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
/* draw channels */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)(-NLACHANNEL_HEIGHT(snla));
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -661,11 +663,12 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= NLACHANNEL_STEP(snla);
+ channel_index++;
}
}
{ /* second pass: UI widgets */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index a883f350f1c..19e6f5a8100 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -111,6 +111,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -133,6 +135,15 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
/* try entering tweakmode if valid */
ok |= BKE_nla_tweakmode_enter(adt);
+
+ /* mark the active track as being "solo"? */
+ if (do_solo && adt->actstrip) {
+ NlaTrack *nlt = BKE_nlatrack_find_tweaked(adt);
+
+ if (nlt && !(nlt->flag & NLATRACK_SOLO)) {
+ BKE_nlatrack_solo_toggle(adt, nlt);
+ }
+ }
}
/* free temp data */
@@ -159,6 +170,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
void NLA_OT_tweakmode_enter(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Enter Tweak Mode";
ot->idname = "NLA_OT_tweakmode_enter";
@@ -170,16 +183,22 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Enable 'solo' on the NLA Track containing the active strip, "
+ "to edit it without seeing the effects of the NLA stack");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------- */
/* NLA Editor internal API function for exiting tweakmode */
-bool nlaedit_disable_tweakmode(bAnimContext *ac)
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter;
+ int filter;
/* get a list of the AnimData blocks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
@@ -195,7 +214,14 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
- /* to be sure, just exit tweakmode... */
+ /* clear solo flags */
+ if ((do_solo) & (adt->flag & ADT_NLA_SOLO_TRACK) &&
+ (adt->flag & ADT_NLA_EDIT_ON))
+ {
+ BKE_nlatrack_solo_toggle(adt, NULL);
+ }
+
+ /* to be sure that we're doing everything right, just exit tweakmode... */
BKE_nla_tweakmode_exit(adt);
}
@@ -218,9 +244,11 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
}
/* exit tweakmode operator callback */
-static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
+static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -228,7 +256,7 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* perform operation */
- ok = nlaedit_disable_tweakmode(&ac);
+ ok = nlaedit_disable_tweakmode(&ac, do_solo);
/* success? */
if (ok)
@@ -239,6 +267,8 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_tweakmode_exit(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Exit Tweak Mode";
ot->idname = "NLA_OT_tweakmode_exit";
@@ -250,6 +280,12 @@ void NLA_OT_tweakmode_exit(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Disable 'solo' on any of the NLA Tracks after exiting tweak mode "
+ "to get things back to normal");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* *********************************************** */
@@ -382,7 +418,7 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa
y = (float)NLACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -2189,7 +2225,7 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
/* check if modifier is valid for this context */
if (fmi == NULL)
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index bd96b5a4de5..344580c0d15 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -83,7 +83,7 @@ enum eNlaEdit_Snap_Mode {
/* --- */
-bool nlaedit_disable_tweakmode(bAnimContext *ac);
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
void NLA_OT_tweakmode_exit(wmOperatorType *ot);
@@ -137,6 +137,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac);
void NLA_OT_channels_click(wmOperatorType *ot);
void NLA_OT_action_pushdown(wmOperatorType *ot);
+void NLA_OT_action_unlink(wmOperatorType *ot);
void NLA_OT_tracks_add(wmOperatorType *ot);
void NLA_OT_tracks_delete(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index b3a875047db..98da10470f8 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -114,6 +114,7 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_channels_click);
WM_operatortype_append(NLA_OT_action_pushdown);
+ WM_operatortype_append(NLA_OT_action_unlink);
WM_operatortype_append(NLA_OT_tracks_add);
WM_operatortype_append(NLA_OT_tracks_delete);
@@ -305,6 +306,7 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
void nla_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
/* keymap for all regions ------------------------------------------- */
keymap = WM_keymap_find(keyconf, "NLA Generic", SPACE_NLA, 0);
@@ -319,6 +321,16 @@ void nla_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
+ /* tweakmode for stashed actions
+ * - similar to normal tweakmode, except we mark the tracks as being "solo"
+ * too so that the action can be edited in isolation
+ */
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 6fa164a483f..7f35884cb65 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -703,7 +703,9 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
- if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) {
+ if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ RNA_boolean_get(ptr, "has_layers"))
+ {
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
}
@@ -829,7 +831,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
}
static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -862,14 +864,15 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
uiLayout *row = uiLayoutRow(layout, true);
+ const bool is_packed = BKE_image_has_packedfile(ima);
- if (ima->packedfile)
+ if (is_packed)
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiLayoutSetEnabled(row, !is_packed);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -1214,6 +1217,24 @@ static void node_shader_set_butfunc(bNodeType *ntype)
/* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
+static void node_buts_image_views(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr,
+ PointerRNA *imaptr)
+{
+ uiLayout *col;
+
+ if (!imaptr->data)
+ return;
+
+ col = uiLayoutColumn(layout, false);
+
+ if (RNA_boolean_get(ptr, "has_views")) {
+ if (RNA_enum_get(ptr, "view") == 0)
+ uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ else
+ uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ }
+}
+
static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -1227,6 +1248,8 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
imaptr = RNA_pointer_get(ptr, "image");
node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
+
+ node_buts_image_views(layout, C, ptr, &imaptr);
}
static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1236,7 +1259,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1);
}
static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1717,8 +1740,8 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
-
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
if (multilayer)
uiItemL(layout, IFACE_("Path:"), ICON_NONE);
else
@@ -1727,15 +1750,22 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
uiLayout *row, *col;
int active_index;
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
uiTemplateImageSettings(layout, &imfptr, false);
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
+
uiItemS(layout);
uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
@@ -1797,6 +1827,9 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
}
}
}
@@ -2090,6 +2123,18 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
}
+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);
+}
+
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row;
@@ -2587,6 +2632,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SWITCH:
ntype->draw_buttons = node_composit_buts_switch;
break;
+ case CMP_NODE_SWITCH_VIEW:
+ ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
+ break;
case CMP_NODE_MASK_BOX:
ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
@@ -2739,7 +2787,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA
PointerRNA iuserptr;
RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
- uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
+ uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
}
static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2959,6 +3007,7 @@ static void node_file_output_socket_draw(bContext *C, uiLayout *layout, PointerR
imfptr = RNA_pointer_get(node_ptr, "format");
imtype = RNA_enum_get(&imfptr, "file_format");
+
if (imtype == R_IMF_IMTYPE_MULTILAYER) {
NodeImageMultiFileSocket *input = sock->storage;
RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 87a64e95e63..34efba00b86 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -123,7 +123,14 @@ void ED_node_tag_update_id(ID *id)
bNodeTree *ntree = node_tree_from_ID(id);
if (id == NULL || ntree == NULL)
return;
-
+
+ /* TODO(sergey): With the new dependency graph it
+ * should be just enough to only tag ntree itself,
+ * all the users of this tree will have update
+ * flushed from the tree,
+ */
+ DAG_id_tag_update(&ntree->id, 0);
+
if (ntree->type == NTREE_SHADER) {
DAG_id_tag_update(id, 0);
@@ -163,14 +170,14 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
ntreeTexCheckCyclics(ntree);
}
-static int compare_nodes(bNode *a, bNode *b)
+static bool compare_nodes(const bNode *a, const bNode *b)
{
bNode *parent;
/* These tell if either the node or any of the parent nodes is selected.
* A selected parent means an unselected node is also in foreground!
*/
- int a_select = (a->flag & NODE_SELECT), b_select = (b->flag & NODE_SELECT);
- int a_active = (a->flag & NODE_ACTIVE), b_active = (b->flag & NODE_ACTIVE);
+ bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
+ bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
/* if one is an ancestor of the other */
/* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index f79d6e26f22..ffd51bcc44e 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -93,7 +93,6 @@ typedef struct CompoJob {
const short *stop;
short *do_update;
float *progress;
- short need_sync;
int recalc_flags;
} CompoJob;
@@ -162,13 +161,12 @@ static int compo_breakjob(void *cjv)
);
}
-/* called by compo, wmJob sends notifier, old compositor system only */
-static void compo_statsdrawjob(void *cjv, char *UNUSED(str))
+/* called by compo, wmJob sends notifier */
+static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
{
CompoJob *cj = cjv;
*(cj->do_update) = true;
- cj->need_sync = true;
}
/* called by compo, wmJob sends notifier */
@@ -202,17 +200,8 @@ static void compo_initjob(void *cjv)
}
/* called before redraw notifiers, it moves finished previews over */
-static void compo_updatejob(void *cjv)
+static void compo_updatejob(void *UNUSED(cjv))
{
- CompoJob *cj = cjv;
-
- if (cj->need_sync) {
- /* was used by old compositor system only */
- ntreeLocalSync(cj->localtree, cj->ntree);
-
- cj->need_sync = false;
- }
-
WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
}
@@ -223,13 +212,13 @@ static void compo_progressjob(void *cjv, float progress)
*(cj->progress) = progress;
}
-
/* only this runs inside thread */
static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
{
CompoJob *cj = cjv;
bNodeTree *ntree = cj->localtree;
Scene *scene = cj->scene;
+ SceneRenderView *srv;
if (scene->use_nodes == false)
return;
@@ -249,7 +238,16 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
// XXX BIF_store_spare();
/* 1 is do_previews */
- ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings);
+
+ if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, "");
+ }
+ else {
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
+ }
+ }
ntree->test_break = NULL;
ntree->stats_draw = NULL;
@@ -742,6 +740,34 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+void ED_node_id_unref(SpaceNode *snode, const ID *id)
+{
+ if (GS(id->name) == ID_SCE) {
+ if (snode->id == id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ bNodeTreePath *path, *path_next;
+ for (path = snode->treepath.first; path; path = path_next) {
+ path_next = path->next;
+ MEM_freeN(path);
+ }
+ BLI_listbase_clear(&snode->treepath);
+
+ snode->id = NULL;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(id->name) == ID_OB) {
+ if (snode->from == id) {
+ snode->flag &= ~SNODE_PIN;
+ snode->from = NULL;
+ }
+ }
+}
+
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
@@ -1671,6 +1697,54 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** Switch View ******************* */
+
+static int node_switch_view_poll(bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if (snode && snode->edittree)
+ return true;
+
+ return false;
+}
+
+static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node, *next;
+
+ for (node = snode->edittree->nodes.first; node; node = next) {
+ next = node->next;
+ if (node->flag & SELECT) {
+ /* call the update function from the Switch View node */
+ node->update = NODE_UPDATE_OPERATOR;
+ }
+ }
+
+ ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_switch_view_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Views";
+ ot->description = "Update views of selected node";
+ ot->idname = "NODE_OT_switch_view_update";
+
+ /* api callbacks */
+ ot->exec = node_switch_view_exec;
+ ot->poll = node_switch_view_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ****************** Delete with reconnect ******************* */
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index b69808d4e81..f1d9d4efcc6 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -456,8 +456,8 @@ static int node_group_separate_selected(bNodeTree *ntree, bNodeTree *ngroup, flo
/* add internal links to the ntree */
for (link = ngroup->links.first; link; link = link_next) {
- int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
- int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
+ const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
+ const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
link_next = link->next;
if (make_copy) {
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 27c3ab813ae..b15e9025a82 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -42,12 +42,9 @@ struct ARegionType;
struct View2D;
struct bContext;
struct wmWindow;
-struct wmWindowManager;
-struct wmEvent;
struct bNode;
struct bNodeSocket;
struct bNodeLink;
-struct Main;
struct wmKeyConfig;
/* temp data to pass on to modal */
@@ -203,6 +200,8 @@ void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
+void NODE_OT_switch_view_update (struct wmOperatorType *ot);
+
/* Note: clipboard_cut is a simple macro of copy + delete */
void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index e2d83c243a2..474ad4db4af 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -123,6 +123,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_viewer_border);
WM_operatortype_append(NODE_OT_clear_viewer_border);
+ WM_operatortype_append(NODE_OT_switch_view_update);
+
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
WM_operatortype_append(NODE_OT_tree_socket_move);
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 25f9d56c8f0..78302fedd97 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -249,9 +249,9 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
bool changed = false;
const unsigned int delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
- char *sep, *suf_act, *suf_curr;
+ const char *sep, *suf_act, *suf_curr;
- pref_len_act = BLI_str_partition_ex_utf8(node_act->name, delims, &sep, &suf_act, from_right);
+ pref_len_act = BLI_str_partition_ex_utf8(node_act->name, NULL, delims, &sep, &suf_act, from_right);
/* Note: in case we are searching for suffix, and found none, use whole name as suffix. */
if (from_right && !(sep && suf_act)) {
@@ -263,7 +263,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
if (node->flag & SELECT) {
continue;
}
- pref_len_curr = BLI_str_partition_ex_utf8(node->name, delims, &sep, &suf_curr, from_right);
+ pref_len_curr = BLI_str_partition_ex_utf8(node->name, NULL, delims, &sep, &suf_curr, from_right);
/* Same as with active node name! */
if (from_right && !(sep && suf_curr)) {
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 8b68ac013c2..a7fd624d2aa 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -24,6 +24,7 @@
* \ingroup edinterface
*/
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -214,8 +215,22 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
}
else if (!node_from) {
node_from = nodeAddStaticNode(C, ntree, type);
- node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
- node_from->locy = node_to->locy;
+ if (node_prev != NULL) {
+ /* If we're replacing existing node, use it's location. */
+ node_from->locx = node_prev->locx;
+ node_from->locy = node_prev->locy;
+ node_from->offsetx = node_prev->offsetx;
+ node_from->offsety = node_prev->offsety;
+ }
+ else {
+ /* Avoid exact intersection of nodes.
+ * TODO(sergey): Still not ideal, but better than nothing.
+ */
+ int index = BLI_findindex(&node_to->inputs, sock_to);
+ BLI_assert(index != -1);
+ node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
+ node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
+ }
node_link_item_apply(node_from, item);
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 3491ecc86af..8c5d2d82468 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -292,7 +292,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot)
ot->cancel = snode_bg_viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
static int backimage_zoom_exec(bContext *C, wmOperator *op)
@@ -609,8 +609,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index 62cb0bc73cd..de90c417bdd 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -203,12 +203,10 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
value[0] = '\0';
for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
if (i == 0) {
- BLI_strncpy(value, path->node_name, max_length);
- size = strlen(path->node_name);
+ size = BLI_strncpy_rlen(value, path->node_name, max_length);
}
else {
- BLI_snprintf(value, max_length, "/%s", path->node_name);
- size = strlen(path->node_name) + 1;
+ size = BLI_snprintf_rlen(value, max_length, "/%s", path->node_name);
}
max_length -= size;
if (max_length <= 0)
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 2c61e69d611..420b73cee86 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -198,11 +198,11 @@ static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob
ID *id;
bAction *action;
FCurve *fcu;
- bool driven;
+ bool driven, special;
RNA_id_pointer_create(&ob->id, &ptr);
prop = RNA_struct_find_property(&ptr, rnapropname);
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven);
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special);
if (fcu && !driven) {
id = ptr.id.data;
@@ -290,8 +290,7 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
Object *ob = (Object *)poin2;
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
@@ -1122,6 +1121,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
case eModifierType_SimpleDeform:
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 798dae2cef3..0821304abf3 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -39,20 +39,24 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_mempool.h"
#include "BLF_translation.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_material.h"
#include "BKE_group.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_keyframing.h"
@@ -785,7 +789,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
-// XXX if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
+// XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound);
// }
// else return; /* XXX RETURN! XXX */
@@ -1952,3 +1956,36 @@ void OUTLINER_OT_group_link(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
}
+
+/******** Utils to clear any ref to freed ID... **********/
+
+void ED_outliner_id_unref(SpaceOops *so, const ID *id)
+{
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == id) {
+ so->search_tse.id = NULL;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == id) {
+ tselem->id = NULL;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 50fecebb742..24842d20573 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,12 +36,10 @@
/* internal exports only */
-struct wmWindowManager;
struct wmOperatorType;
struct TreeStoreElem;
struct bContext;
struct Scene;
-struct ARegion;
struct ID;
struct Object;
@@ -59,6 +57,11 @@ typedef struct TreeElement {
PointerRNA rnaptr; // RNA Pointer
} TreeElement;
+#define TREESTORE_ID_TYPE(_id) \
+ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
+ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
+ ELEM(GS((_id)->name), ID_SCR, ID_WM)) /* Only in 'blendfile' mode ... :/ */
+
/* TreeElement->flag */
#define TE_ACTIVE 1
#define TE_ICONROW 2
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 730ee02f448..e52c68b57e9 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -554,10 +554,12 @@ static eOLDrawState tree_element_active_bone(
Object *ob = OBACT;
if (ob) {
if (set != OL_SETSEL_EXTEND) {
- bPoseChannel *pchannel;
/* single select forces all other bones to get unselected */
- for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
- pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ Bone *bone;
+ for (bone = arm->bonebase.first; bone != NULL; bone = bone->next) {
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone, false);
+ }
}
}
@@ -618,7 +620,7 @@ static eOLDrawState tree_element_active_ebone(
if (set != OL_SETSEL_NONE) {
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_deselect_all(scene->obedit, 0); // deselect
+ ED_armature_deselect_all(scene->obedit);
tree_element_active_ebone__sel(C, scene, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 64e00589712..66863b8061b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -427,8 +427,7 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
{
Group *group = (Group *)tselem->id;
- Object *ob = ED_object_add_type(C, OB_EMPTY, scene->cursor, NULL, false, scene->layact);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -467,7 +466,7 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_free_animdata(tselem->id);
+ BKE_animdata_free(tselem->id);
}
@@ -694,23 +693,26 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
-static void outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
{
- Base *child_base;
+ Base *child_base, *base_next;
Object *parent;
if (!base) {
- return;
+ return NULL;
}
- for (child_base = scene->base.first; child_base; child_base = child_base->next) {
+ for (child_base = scene->base.first; child_base; child_base = base_next) {
+ base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
- outline_delete_hierarchy(C, scene, child_base);
+ base_next = outline_delete_hierarchy(C, scene, child_base);
}
}
+ base_next = base->next;
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ return base_next;
}
static void object_delete_hierarchy_cb(
@@ -943,16 +945,15 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
default:
BLI_assert(0);
}
-
if (event == 3) { /* instance */
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(CTX_data_main(C));
}
-
- ED_undo_push(C, prop_group_op_types[event].name);
+
+ ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1652,9 +1653,14 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
+ uiBut *but = UI_context_active_but_get(C);
TreeElement *te;
float fmval[2];
+ if (but) {
+ UI_but_tooltip_timer_remove(C, but);
+ }
+
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 7aac6a7797c..d4bef06cca9 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -66,7 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_sequencer.h"
#include "BKE_idcode.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_armature.h"
#include "ED_screen.h"
@@ -104,6 +104,8 @@ static void outliner_storage_cleanup(SpaceOops *soops)
/* cleanup only after reading file or undo step, and always for
* RNA datablocks view in order to save memory */
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
+ soops->storeflag &= ~SO_TREESTORE_CLEANUP;
+
BLI_mempool_iternew(ts, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
if (tselem->id == NULL) unused++;
@@ -114,7 +116,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
BLI_mempool_destroy(ts);
soops->treestore = NULL;
if (soops->treehash) {
- BKE_treehash_free(soops->treehash);
+ BKE_outliner_treehash_free(soops->treehash);
soops->treehash = NULL;
}
}
@@ -133,7 +135,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
soops->treestore = new_ts;
if (soops->treehash) {
/* update hash table to fix broken pointers */
- BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
}
}
@@ -151,12 +153,12 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
}
if (soops->treehash == NULL) {
- soops->treehash = BKE_treehash_create_from_treestore(soops->treestore);
+ soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
}
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id);
+ tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -171,7 +173,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
tselem->used = 0;
tselem->flag = TSE_CLOSED;
te->store_elem = tselem;
- BKE_treehash_add_element(soops->treehash, tselem);
+ BKE_outliner_treehash_add_element(soops->treehash, tselem);
}
/* ********************************************************* */
@@ -216,7 +218,7 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
if (tse->id == NULL) return NULL;
/* check if 'tse' is in treestore */
- tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
+ tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
if (tselem)
return outliner_find_tree_element(&soops->tree, tselem);
@@ -769,16 +771,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
- ebone->temp = ten;
+ ebone->temp.p = ten;
}
/* make hierarchy */
- ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp : NULL;
+ ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
while (ten) {
TreeElement *nten = ten->next, *par;
ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp;
+ par = ebone->parent->temp.p;
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -855,6 +857,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
return NULL;
}
+ if (type == 0) {
+ /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
+ BLI_assert(TREESTORE_ID_TYPE(id));
+ }
+
te = MEM_callocN(sizeof(TreeElement), "tree elem");
/* add to the visual tree */
BLI_addtail(lb, te);
@@ -1573,6 +1580,11 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
+ if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
+ soops->storeflag &= ~SO_TREESTORE_REBUILD;
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ }
+
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index e1aea8892b5..7b1ec174a6b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -41,7 +41,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -464,7 +464,7 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(soutliner->treestore);
}
if (soutliner->treehash) {
- BKE_treehash_free(soutliner->treehash);
+ BKE_outliner_treehash_free(soutliner->treehash);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 38a01bcd78c..86d1fe71ade 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <ctype.h>
#include "MEM_guardedalloc.h"
@@ -60,6 +61,7 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "UI_interface.h"
#include "BKE_sound.h"
@@ -70,6 +72,10 @@
/* own include */
#include "sequencer_intern.h"
+typedef struct SequencerAddData {
+ ImageFormatData im_format;
+} SequencerAddData;
+
/* Generic functions, reused by add strip operators */
/* avoid passing multiple args and be more verbose */
@@ -222,6 +228,19 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
}
RNA_PROP_END;
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_multiview")) && RNA_property_boolean_get(op->ptr, prop)) {
+ if (op->customdata) {
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+
+ seq_load->views_format = imf->views_format;
+ seq_load->flag |= SEQ_USE_VIEWS;
+
+ /* operator custom data is always released after the SeqLoadInfo, no need to handle the memory here */
+ seq_load->stereo3d_format = &imf->stereo3d_format;
+ }
+ }
}
/**
@@ -287,7 +306,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
- seq->scene_sound = sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
@@ -573,6 +592,9 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_CANCELLED;
}
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
@@ -581,15 +603,40 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
+/* add sequencer operators */
+static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
+{
+ op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
+}
+
+static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
+
+static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
}
-
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* This is for drag and drop */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -599,13 +646,37 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
-
+
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
//return sequencer_add_movie_strip_exec(C, op);
}
+static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
@@ -618,9 +689,11 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -679,11 +752,74 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
}
+int sequencer_image_seq_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
+{
+ int minframe = INT32_MAX, maxframe = INT32_MIN;
+ int numdigits = 0;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename;
+ int frame;
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+
+ if (filename) {
+ if (BLI_path_frame_get(filename, &frame, &numdigits)) {
+ minframe = min_ii(minframe, frame);
+ maxframe = max_ii(maxframe, frame);
+ }
+
+ MEM_freeN(filename);
+ }
+ }
+ RNA_END;
+
+ if (minframe == INT32_MAX) {
+ minframe = sfra;
+ maxframe = minframe + 1;
+ }
+
+ *r_minframe = minframe;
+ *r_numdigits = numdigits;
+
+ return maxframe - minframe + 1;
+}
+
+void sequencer_image_seq_reserve_frames(wmOperator *op, StripElem *se, int len, int minframe, int numdigits)
+{
+ int i;
+ char *filename = NULL;
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ break;
+ }
+ RNA_END;
+
+ if (filename) {
+ char ext[PATH_MAX];
+ char filename_stripped[PATH_MAX];
+ /* strip the frame from filename and substitute with # */
+ BLI_path_frame_strip(filename, true, ext);
+
+ for (i = 0; i < len; i++, se++) {
+ BLI_strncpy(filename_stripped, filename, sizeof(filename_stripped));
+ BLI_path_frame(filename_stripped, minframe + i, numdigits);
+ BLI_snprintf(se->name, sizeof(se->name), "%s%s", filename_stripped, ext);
+ }
+
+ MEM_freeN(filename);
+ }
+}
+
+
/* add image operator */
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
+ int minframe, numdigits;
/* cant use the generic function for this */
-
Scene *scene = CTX_data_scene(C); /* only for sound */
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
@@ -691,11 +827,17 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
Strip *strip;
StripElem *se;
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, op);
/* images are unique in how they handle this - 1 per strip elem */
- seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ if (use_placeholders) {
+ seq_load.len = sequencer_image_seq_get_minmax_frame(op, seq_load.start_frame, &minframe, &numdigits);
+ }
+ else {
+ seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (seq_load.len == 0)
return OPERATOR_CANCELLED;
@@ -703,20 +845,24 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
if (seq_load.flag & SEQ_LOAD_REPLACE_SEL)
ED_sequencer_deselect_all(scene);
-
/* main adding function */
seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
if (seq_load.len == 1) {
if (seq_load.start_frame < seq_load.end_frame) {
@@ -735,6 +881,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_overlap(C, op, seq);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -742,6 +891,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@@ -750,6 +902,12 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -766,6 +924,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
@@ -775,6 +935,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b63c46cba01..27eb28bec8f 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -50,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -62,6 +63,7 @@
#include "ED_markers.h"
#include "ED_mask.h"
#include "ED_sequencer.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "UI_interface.h"
@@ -424,12 +426,12 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
size_t numstr_len;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->startdisp);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp);
x1 = rx1;
y1 -= 0.45f;
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
x1 = x2 - handsize_clamped * 0.75f;
y1 = y2 + 0.05f;
}
@@ -860,7 +862,7 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs)
+ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
{
SeqRenderData context;
ImBuf *ibuf;
@@ -888,6 +890,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
bmain->eval_ctx, bmain, scene,
rectx, recty, proxy_size,
&context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@@ -978,6 +981,76 @@ static void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrec
}
}
+static void sequencer_draw_gpencil(const bContext *C)
+{
+ /* draw grease-pencil (image aligned) */
+ ED_gpencil_draw_2dimage(C);
+
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
+
+ /* draw grease-pencil (screen aligned) */
+ ED_gpencil_draw_view2d(C, 0);
+}
+
+/* draws content borders plus safety borders if needed */
+static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
+{
+ float x1 = v2d->tot.xmin;
+ float y1 = v2d->tot.ymin;
+ float x2 = v2d->tot.xmax;
+ float y2 = v2d->tot.ymax;
+
+ /* border */
+ setlinestyle(3);
+
+ UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x1 - 0.5f, y1 - 0.5f);
+ glVertex2f(x1 - 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y1 - 0.5f);
+ glEnd();
+
+ /* safety border */
+ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
+
+ if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
+ }
+
+ setlinestyle(0);
+}
+
+/* draws checkerboard background for transparent content */
+static void sequencer_draw_background(const SpaceSeq *sseq, View2D *v2d, const float viewrect[2])
+{
+ /* setting up the view */
+ UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
+ UI_view2d_curRect_validate(v2d);
+ UI_view2d_view_ortho(v2d);
+
+ /* only draw alpha for main buffer */
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ if (sseq->flag & SEQ_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ }
+ }
+}
+
void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_backdrop)
{
struct Main *bmain = CTX_data_main(C);
@@ -994,6 +1067,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq);
int format, type;
bool glsl_used = false;
+ const bool draw_gpencil = ((sseq->flag & SEQ_SHOW_GPENCIL) && sseq->gpd);
+ 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) {
/* stop all running jobs, except screen one. currently previews frustrate Render
@@ -1015,6 +1091,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glClear(GL_COLOR_BUFFER_BIT);
}
+ /* without this colors can flicker from previous opengl state */
+ glColor4ub(255, 255, 255, 255);
+
/* only initialize the preview if a render is in progress */
if (G.is_rendering)
return;
@@ -1023,17 +1102,27 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
return;
}
- ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs);
-
- if (ibuf == NULL)
- return;
+ /* for now we only support Left/Right */
+ ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
+
+ if ((ibuf == NULL) ||
+ (ibuf->rect == NULL && ibuf->rect_float == NULL))
+ {
+ /* gpencil can also be drawn without a valid imbuf */
+ if (draw_gpencil && is_imbuf) {
+ sequencer_display_size(scene, sseq, viewrect);
+
+ sequencer_draw_background(sseq, v2d, viewrect);
+ sequencer_draw_borders(sseq, v2d, scene);
- if (ibuf->rect == NULL && ibuf->rect_float == NULL)
+ sequencer_draw_gpencil(C);
+ }
return;
+ }
sequencer_display_size(scene, sseq, viewrect);
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0) {
+ if (!draw_backdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) {
SequencerScopes *scopes = &sseq->scopes;
sequencer_check_scopes(scopes, ibuf);
@@ -1079,36 +1168,23 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
/* future files may have new scopes we don't catch above */
if (scope) {
scopes->reference_ibuf = ibuf;
- viewrect[0] = scope->x;
- viewrect[1] = scope->y;
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ /* scopes drawn in image preview use viewrect from orig ibuf - currently that's only zebra */
+ }
+ else {
+ viewrect[0] = scope->x;
+ viewrect[1] = scope->y;
+ }
}
else {
scopes->reference_ibuf = NULL;
}
}
- /* without this colors can flicker from previous opengl state */
- glColor4ub(255, 255, 255, 255);
-
if (!draw_backdrop) {
- UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
- UI_view2d_curRect_validate(v2d);
-
- /* setting up the view - actual drawing starts here */
- UI_view2d_view_ortho(v2d);
-
- /* only draw alpha for main buffer */
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
- if (sseq->flag & SEQ_USE_ALPHA) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
- glColor4f(1.0, 1.0, 1.0, 1.0);
- }
- }
+ sequencer_draw_background(sseq, v2d, viewrect);
}
-
+
if (scope) {
IMB_freeImBuf(ibuf);
ibuf = scope;
@@ -1229,10 +1305,12 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
}
else if (draw_backdrop) {
- float aspect = BLI_rcti_size_x(&ar->winrct) / (float)BLI_rcti_size_y(&ar->winrct);
+ float aspect;
float image_aspect = viewrect[0] / viewrect[1];
float imagex, imagey;
-
+
+ aspect = BLI_rcti_size_x(&ar->winrct) / (float)BLI_rcti_size_y(&ar->winrct);
+
if (aspect >= image_aspect) {
imagex = image_aspect / aspect;
imagey = 1.0f;
@@ -1241,28 +1319,22 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
imagex = 1.0f;
imagey = aspect / image_aspect;
}
-
+
glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex, -imagey);
glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex, imagey);
glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex, imagey);
glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex, -imagey);
}
else {
+ draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0);
+
glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax);
glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
}
glEnd();
-
- if (draw_backdrop) {
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-
- }
-
+
glBindTexture(GL_TEXTURE_2D, last_texid);
glDisable(GL_TEXTURE_2D);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
@@ -1277,63 +1349,29 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (!scope)
IMB_freeImBuf(ibuf);
-
+
+ if (draw_metadata) {
+ ED_region_image_metadata_draw(0.0, 0.0, ibuf, v2d->tot, 1.0, 1.0);
+ }
+
if (draw_backdrop) {
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
return;
}
-
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
-
- float x1 = v2d->tot.xmin;
- float y1 = v2d->tot.ymin;
- float x2 = v2d->tot.xmax;
- float y2 = v2d->tot.ymax;
-
- /* border */
- setlinestyle(3);
-
- UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(x1 - 0.5f, y1 - 0.5f);
- glVertex2f(x1 - 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y1 - 0.5f);
- glEnd();
-
- /* safety border */
- if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
- UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title,
- scene->safe_areas.action);
-
- if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
- UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title_center,
- scene->safe_areas.action_center);
- }
- }
- setlinestyle(0);
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ sequencer_draw_borders(sseq, v2d, scene);
}
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (image aligned) */
- ED_gpencil_draw_2dimage(C);
- }
+
+ if (draw_gpencil && is_imbuf) {
+ sequencer_draw_gpencil(C);
}
-
- /* ortho at pixel level */
- UI_view2d_view_restore(C);
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (screen aligned) */
- ED_gpencil_draw_view2d(C, 0);
- }
+ else {
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index aaf398bf3a1..7c43720ae2b 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -180,8 +180,6 @@ static void seq_proxy_build_job(const bContext *C)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
ScrArea *sa = CTX_wm_area(C);
- struct SeqIndexBuildContext *context;
- LinkData *link;
Sequence *seq;
GSet *file_list;
@@ -209,9 +207,7 @@ static void seq_proxy_build_job(const bContext *C)
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
- context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list);
- link = BLI_genericNodeN(context);
- BLI_addtail(&pj->queue, link);
+ BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
}
}
SEQ_END
@@ -988,11 +984,11 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
return;
BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
-// XXX if (0 == sbutton(from, 0, sizeof(from)-1, "From: "))
+// XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
// return;
BLI_strncpy(to, from, sizeof(to));
-// XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: "))
+// XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
// return;
if (STREQ(to, from))
@@ -1742,7 +1738,7 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Mute Strips";
ot->idname = "SEQUENCER_OT_mute";
- ot->description = "Mute selected strips";
+ ot->description = "Mute (un)selected strips";
/* api callbacks */
ot->exec = sequencer_mute_exec;
@@ -1793,7 +1789,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Un-Mute Strips";
ot->idname = "SEQUENCER_OT_unmute";
- ot->description = "Un-Mute unselected rather than selected strips";
+ ot->description = "Unmute (un)selected strips";
/* api callbacks */
ot->exec = sequencer_unmute_exec;
@@ -1802,7 +1798,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "UnMute unselected rather than selected strips");
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips");
}
@@ -3165,7 +3161,7 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
else if (seq->scene_sound) {
- sound_remove_scene_sound(scene, seq->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq->scene_sound = NULL;
}
}
@@ -3322,10 +3318,10 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
}
if (seq_act->scene_sound)
- sound_remove_scene_sound(scene, seq_act->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_act->scene_sound);
if (seq_other->scene_sound)
- sound_remove_scene_sound(scene, seq_other->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_other->scene_sound);
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
@@ -3333,8 +3329,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
BKE_sequence_calc(scene, seq_act);
BKE_sequence_calc(scene, seq_other);
- if (seq_act->sound) sound_add_scene_sound_defaults(scene, seq_act);
- if (seq_other->sound) sound_add_scene_sound_defaults(scene, seq_other);
+ 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);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3442,12 +3438,18 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
SEQP_BEGIN(ed, seq)
{
if ((seq->flag & SELECT)) {
- struct SeqIndexBuildContext *context;
+ ListBase queue = {NULL, NULL};
+ LinkData *link;
short stop = 0, do_update;
float progress;
- context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list);
- BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
- BKE_sequencer_proxy_rebuild_finish(context, 0);
+
+ BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
+
+ for (link = queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+ BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
+ BKE_sequencer_proxy_rebuild_finish(context, 0);
+ }
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
}
@@ -3692,12 +3694,21 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq = BKE_sequencer_active_get(scene);
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
+ int minframe, numdigits;
if (seq->type == SEQ_TYPE_IMAGE) {
char directory[FILE_MAX];
- const int len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ int len;
StripElem *se;
+ /* need to find min/max frame for placeholders */
+ if (use_placeholders) {
+ len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
+ }
+ else {
+ len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (len == 0)
return OPERATOR_CANCELLED;
@@ -3715,14 +3726,19 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
}
seq->strip->stripdata = se = MEM_callocN(len * sizeof(StripElem), "stripelem");
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
/* reset these else we wont see all the images */
seq->anim_startofs = seq->anim_endofs = 0;
@@ -3797,4 +3813,5 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY);
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 461c72961c2..eaac43095e8 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -45,7 +45,8 @@ struct ARegion;
struct ARegionType;
struct Scene;
struct Main;
-struct SequencePreview;
+struct wmOperator;
+struct StripElem;
/* space_sequencer.c */
struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
@@ -63,7 +64,7 @@ void sequencer_special_update_set(Sequence *seq);
/* UNUSED */
// void seq_reset_imageofs(struct SpaceSeq *sseq);
-struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs);
+struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
/* sequencer_edit.c */
struct View2D;
@@ -196,6 +197,7 @@ void SEQUENCER_OT_properties(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_add(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_remove(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_move(struct wmOperatorType *ot);
+void SEQUENCER_OT_strip_modifier_copy(struct wmOperatorType *ot);
/* sequencer_view.c */
void SEQUENCER_OT_sample(struct wmOperatorType *ot);
@@ -203,5 +205,9 @@ void SEQUENCER_OT_sample(struct wmOperatorType *ot);
/* sequencer_preview.c */
void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq);
+/* sequencer_add */
+int sequencer_image_seq_get_minmax_frame(struct wmOperator *op, int sfra, int *r_minframe, int *r_numdigits);
+void sequencer_image_seq_reserve_frames(struct wmOperator *op, struct StripElem *se, int len, int minframe, int numdigits);
+
#endif /* __SEQUENCER_INTERN_H__ */
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index 83f3f9bc961..fad317fdd4e 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -207,3 +207,58 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
}
+
+static int strip_modifier_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = scene->ed;
+ Sequence *seq = BKE_sequencer_active_get(scene);
+ Sequence *seq_iter;
+
+ if (!seq || !seq->modifiers.first)
+ return OPERATOR_CANCELLED;
+
+ SEQP_BEGIN(ed, seq_iter)
+ {
+ if (seq_iter->flag & SELECT) {
+ if (seq_iter == seq)
+ continue;
+
+ if (seq_iter->modifiers.first) {
+ SequenceModifierData *smd_tmp, *smd = seq_iter->modifiers.first;
+
+ while (smd) {
+ smd_tmp = smd->next;
+ BLI_remlink(&seq_iter->modifiers, smd);
+ BKE_sequence_modifier_free(smd);
+ smd = smd_tmp;
+ }
+ BLI_listbase_clear(&seq_iter->modifiers);
+ }
+
+ BKE_sequence_modifier_list_copy(seq_iter, seq);
+ }
+ }
+ SEQ_END
+
+ BKE_sequence_invalidate_cache(scene, seq);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_modifier_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy to Selected Strips";
+ ot->idname = "SEQUENCER_OT_strip_modifier_copy";
+ ot->description = "Copy modifiers of the active strip to all selected strips";
+
+ /* api callbacks */
+ ot->exec = strip_modifier_copy_exec;
+ ot->poll = strip_modifier_active_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 33a8a1c5b41..dadd187f36c 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -121,6 +121,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_strip_modifier_add);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_remove);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_move);
+ WM_operatortype_append(SEQUENCER_OT_strip_modifier_copy);
/* sequencer_view.h */
WM_operatortype_append(SEQUENCER_OT_sample);
@@ -365,5 +366,5 @@ void ED_operatormacros_sequencer(void)
"Duplicate selected strips and move them", OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
- WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_seq_slide");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
index c8834d394f5..3f908dc7096 100644
--- a/source/blender/editors/space_sequencer/sequencer_preview.c
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -85,7 +85,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
PreviewJobAudio *preview_next;
bSound *sound = previewjb->sound;
- sound_read_waveform(sound, stop);
+ BKE_sound_read_waveform(sound, stop);
if (*stop || G.is_break) {
BLI_mutex_lock(pj->mutex);
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 24b3776da6d..c197aabedfd 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -29,9 +29,9 @@
#include <math.h>
#include <string.h>
-#include "BLI_math_color.h"
#include "BLI_utildefines.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -167,7 +167,7 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
- float v = (float)rgb_to_luma_byte(rgb) / 255.0f;
+ float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
unsigned char *p = tgt;
p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1);
@@ -207,7 +207,7 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
const float *rgb = src + 4 * (ibuf->x * y + x);
- float v = rgb_to_luma(rgb);
+ float v = IMB_colormanagement_get_luminance(rgb);
unsigned char *p = tgt;
CLAMP(v, 0.0f, 1.0f);
@@ -647,13 +647,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
wtable[x] = (unsigned char) (pow(((float) x + 1) / 256, scope_gamma) * 255);
}
- for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ for (x = 0; x < 256; x++) {
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
@@ -694,12 +694,12 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
}
for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 7fdbc9cc7de..4d6ea865b40 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -94,7 +94,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *) CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
@@ -201,8 +201,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: /* XXX hardcoded */
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 7a7f189b187..769718e1567 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -564,7 +564,10 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
SpaceSeq *sseq = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- int show_split = scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW && sseq->mainb == SEQ_DRAW_IMG_IMBUF;
+ const bool show_split = (
+ scene->ed &&
+ (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
+ (sseq->mainb == SEQ_DRAW_IMG_IMBUF));
/* XXX temp fix for wrong setting in sseq->mainb */
if (sseq->mainb == SEQ_DRAW_SEQUENCE) sseq->mainb = SEQ_DRAW_IMG_IMBUF;
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index f577714c480..7ae2617f375 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -34,15 +34,12 @@
/* internal exports only */
struct ARegion;
-struct ARegionType;
struct bContext;
-struct ReportList;
struct ScrArea;
struct SpaceText;
struct Text;
struct TextLine;
struct wmOperatorType;
-struct wmWindowManager;
/* text_draw.c */
void draw_text_main(struct SpaceText *st, struct ARegion *ar);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index ad8050a50e8..fce864d975f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2233,7 +2233,7 @@ void TEXT_OT_scroll(wmOperatorType *ot)
ot->poll = text_scroll_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_INTERNAL;
/* properties */
RNA_def_int(ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
diff --git a/source/blender/editors/space_time/time_intern.h b/source/blender/editors/space_time/time_intern.h
index ce52cbbd65e..ced36b2ac2d 100644
--- a/source/blender/editors/space_time/time_intern.h
+++ b/source/blender/editors/space_time/time_intern.h
@@ -34,7 +34,6 @@
/* internal exports only */
-struct wmWindowManager;
/* time_ops.c */
void time_operatortypes(void);
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index ab69e67361d..d8d29d63686 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../depsgraph
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../intern/smoke/extern
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index a21da940906..78f24948070 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -48,6 +48,7 @@ incs = [
'../../makesrna',
'../../render/extern/include',
'../../windowmanager',
+ '../../depsgraph',
]
if env['WITH_BF_PYTHON']:
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index d8b18140cde..d753ad68fcc 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -51,7 +51,6 @@
#include "BIF_gl.h"
-#include "ED_armature.h"
#include "ED_keyframes_draw.h"
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 755c633531d..96ea5d810bf 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -579,7 +579,7 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc
{
Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
- if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0;
+ if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP;
if (tface || Gtexdraw.is_texpaint)
set_draw_settings_cached(0, tface, ma, Gtexdraw);
@@ -588,15 +588,19 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc
return DM_DRAW_OPTION_NORMAL;
}
-static void update_tface_color_layer(DerivedMesh *dm)
+static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
{
MTFace *tface = DM_get_tessface_data_layer(dm, CD_MTFACE);
MFace *mface = dm->getTessFaceArray(dm);
MCol *finalCol;
int i, j;
- MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
- if (!mcol)
- mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ MCol *mcol = NULL;
+
+ if (use_mcol) {
+ mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
+ if (!mcol)
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ }
if (CustomData_has_layer(&dm->faceData, CD_TEXTURE_MCOL)) {
finalCol = CustomData_get_layer(&dm->faceData, CD_TEXTURE_MCOL);
@@ -771,7 +775,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) {
short matnr = mp->mat_nr;
- int mf_smooth = mp->flag & ME_SMOOTH;
+ const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0;
Material *mat = (me->mat) ? me->mat[matnr] : NULL;
int mode = mat ? mat->game.flag : GEMAT_INVISIBLE;
@@ -937,7 +941,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
else {
drawTFace_userData userData;
- update_tface_color_layer(dm);
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
@@ -1103,7 +1107,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Mesh *me = ob->data;
TexMatCallback data = {scene, ob, me, dm};
bool (*set_face_cb)(void *, int);
- int glsl, picking = (G.f & G_PICKSEL);
+ bool glsl, picking = (G.f & G_PICKSEL) != 0;
/* face hiding callback depending on mode */
if (ob == scene->obedit)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 61c9891e201..8cca1c8b1ef 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -52,6 +52,7 @@
#include "BKE_anim.h" /* for the where_on_path function */
#include "BKE_armature.h"
#include "BKE_camera.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h" /* for the get_constraint_target function */
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
@@ -213,6 +214,7 @@ static void drawcube_size(float size);
static void drawcircle_size(float size);
static void draw_empty_sphere(float size);
static void draw_empty_cone(float size);
+static void draw_box(float vec[8][3], bool solid);
static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
{
@@ -299,11 +301,12 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
return true;
- if (BKE_scene_use_new_shading_nodes(scene))
+ if (v3d->drawtype == OB_TEXTURE)
+ return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
+ else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
+ return true;
+ else
return false;
-
- return ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID);
}
static bool check_alpha_pass(Base *base)
@@ -402,13 +405,13 @@ static const float cosval[CIRCLE_RESOL] = {
static void draw_xyz_wire(const float c[3], float size, int axis)
{
- float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
+ float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
float dim = size * 0.1f;
float dx[3], dy[3], dz[3];
- dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
- dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
- dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
+ dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
+ dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
+ dz[0] = 0.0f; dz[1] = 0.0f; dz[2] = dim;
switch (axis) {
case 0: /* x axis */
@@ -424,7 +427,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to bottom right */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
sub_v3_v3(v2, dy);
@@ -447,7 +450,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to center */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
copy_v3_v3(v2, c);
@@ -465,12 +468,12 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v1);
- mul_v3_fl(dx, 2.f);
+ mul_v3_fl(dx, 2.0f);
add_v3_v3(v1, dx);
glVertex3fv(v1);
- mul_v3_fl(dz, 2.f);
+ mul_v3_fl(dz, 2.0f);
sub_v3_v3(v1, dx);
sub_v3_v3(v1, dz);
@@ -483,7 +486,6 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glEnd();
break;
}
-
}
void drawaxes(float size, char drawtype)
@@ -597,10 +599,10 @@ void drawaxes(float size, char drawtype)
}
-/* Function to draw an Image on a empty Object */
+/* Function to draw an Image on an empty Object */
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
{
- Image *ima = (Image *)ob->data;
+ Image *ima = ob->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
float scale, ofs_x, ofs_y, sca_x, sca_y;
@@ -640,16 +642,13 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
sca_y = 1.0f;
}
- /* Calculate the scale center based on objects origin */
+ /* Calculate the scale center based on object's origin */
ofs_x = ob->ima_ofs[0] * ima_x;
ofs_y = ob->ima_ofs[1] * ima_y;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- /* Make sure we are drawing at the origin */
- glTranslatef(0.0f, 0.0f, 0.0f);
-
/* Calculate Image scale */
scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
@@ -943,7 +942,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* ******************** primitive drawing ******************* */
-/* draws a cube on given the scaling of the cube, assuming that
+/* draws a cube given the scaling of the cube, assuming that
* all required matrices have been set (used for drawing empties)
*/
static void drawcube_size(float size)
@@ -1025,8 +1024,6 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
glPointSize(1.0);
}
-
-
static void spotvolume(float lvec[3], float vvec[3], const float inp)
{
/* camera is at 0,0,0 */
@@ -1035,8 +1032,8 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp)
normalize_v3(lvec);
normalize_v3(vvec); /* is this the correct vector ? */
- cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
- cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
+ cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
+ cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
/* vectors are exactly aligned, use the X axis, this is arbitrary */
if (normalize_v3(plane) == 0.0f)
@@ -1149,6 +1146,52 @@ static void draw_transp_spot_volume(Lamp *la, float x, float z)
glCullFace(GL_BACK);
}
+#ifdef WITH_GAMEENGINE
+static void draw_transp_sun_volume(Lamp *la)
+{
+ float box[8][3];
+
+ /* construct box */
+ box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
+ box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
+ box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
+ box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
+ box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
+ box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
+
+ /* draw edges */
+ draw_box(box, false);
+
+ /* draw faces */
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glDepthMask(0);
+
+ /* draw backside darkening */
+ glCullFace(GL_FRONT);
+
+ glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
+ glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+
+ draw_box(box, true);
+
+ /* draw front side lighting */
+ glCullFace(GL_BACK);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
+
+ draw_box(box, true);
+
+ /* restore state */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+ glDepthMask(1);
+ glDisable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+}
+#endif
+
static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
{
@@ -1161,7 +1204,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
unsigned char curcol[4];
unsigned char col[4];
- /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
+ /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
/* the moment of view3d_draw_transp() call */
const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
const bool drawcone = ((dt > OB_WIRE) &&
@@ -1171,7 +1214,22 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
!(base->flag & OB_FROMDUPLI) &&
!is_view);
- if (drawcone && !v3d->transp) {
+#ifdef WITH_GAMEENGINE
+ const bool drawshadowbox = (
+ (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
+ (dt > OB_WIRE) &&
+ !(G.f & G_PICKSEL) &&
+ (la->type == LA_SUN) &&
+ ((la->mode & LA_SHAD_BUF) ||
+ (la->mode & LA_SHAD_RAY)) &&
+ (la->mode & LA_SHOW_SHADOW_BOX) &&
+ !(base->flag & OB_FROMDUPLI) &&
+ !is_view);
+#else
+ const bool drawshadowbox = false;
+#endif
+
+ if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
return;
@@ -1310,7 +1368,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
x *= y;
/* draw the circle/square at the end of the cone */
- glTranslatef(0.0, 0.0, x);
+ glTranslatef(0.0, 0.0, x);
if (la->mode & LA_SQUARE) {
float tvec[3];
float z_abs = fabsf(z);
@@ -1416,6 +1474,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
dir = -dir;
}
}
+
+#ifdef WITH_GAMEENGINE
+ if (drawshadowbox) {
+ draw_transp_sun_volume(la);
+ }
+#endif
+
}
else if (la->type == LA_AREA) {
setlinestyle(3);
@@ -1499,10 +1564,10 @@ static void draw_limit_line(float sta, float end, const short dflag, unsigned in
static void draw_focus_cross(float dist, float size)
{
glBegin(GL_LINES);
- glVertex3f(-size, 0.f, -dist);
- glVertex3f(size, 0.f, -dist);
- glVertex3f(0.f, -size, -dist);
- glVertex3f(0.f, size, -dist);
+ glVertex3f(-size, 0.0f, -dist);
+ glVertex3f(size, 0.0f, -dist);
+ glVertex3f(0.0f, -size, -dist);
+ glVertex3f(0.0f, size, -dist);
glEnd();
}
@@ -1555,8 +1620,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
/* we're compensating camera size for bundles size,
- * to make it so bundles are always displayed with the same size
- */
+ * to make it so bundles are always displayed with the same size */
copy_v3_v3(camera_size, base->object->size);
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
mul_v3_fl(camera_size, tracking_object->scale);
@@ -1624,7 +1688,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glColor3ubv(ob_wire_col);
}
- glLineWidth(2.f);
+ glLineWidth(2.0f);
glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -1632,7 +1696,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
- glLineWidth(1.f);
+ glLineWidth(1.0f);
}
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1746,6 +1810,238 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
GPU_select_load_id(base->selcol);
}
+static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(near_plane[1]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glVertex3fv(near_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[2]);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(near_plane[3]);
+ glVertex3fv(far_plane[3]);
+ glEnd();
+}
+
+/* camera frame */
+static void drawcamera_frame(float vec[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[3]);
+ glEnd();
+}
+
+/* center point to camera frame */
+static void drawcamera_framelines(float vec[4][3], float origin[3])
+{
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[1]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[2]);
+ glEnd();
+}
+
+static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
+{
+ return (ob == v3d->camera) &&
+ (scene->r.scemode & R_MULTIVIEW) != 0 &&
+ (v3d->stereo3d_flag);
+}
+
+static void drawcamera_stereo3d(
+ Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
+ float vec[4][3], float drawsize, const float scale[3])
+{
+ int i, j;
+ float obmat[4][4];
+ float vec_lr[2][4][3];
+ const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
+ float origin[2][3] = {{0}};
+ float tvec[3];
+ const Camera *cam_lr[2];
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
+
+ zero_v3(tvec);
+
+ glPushMatrix();
+
+ for (i = 0; i < 2; i++) {
+ ob = BKE_camera_multiview_render(scene, ob, names[i]);
+ cam_lr[i] = ob->data;
+
+ glLoadMatrixf(rv3d->viewmat);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
+ glMultMatrixf(obmat);
+
+ copy_m3_m3(vec_lr[i], vec);
+ copy_v3_v3(vec_lr[i][3], vec[3]);
+
+ if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ const float shift_x =
+ ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
+ (drawsize * scale[0] * fac));
+
+ for (j = 0; j < 4; j++) {
+ vec_lr[i][j][0] += shift_x;
+ }
+ }
+
+ if (is_stereo3d_cameras) {
+ /* camera frame */
+ drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
+
+ /* center point to camera frame */
+ drawcamera_framelines(vec_lr[i], tvec);
+ }
+
+ /* connecting line */
+ mul_m4_v3(obmat, origin[i]);
+
+ /* convergence plane */
+ if (is_stereo3d_plane || is_stereo3d_volume) {
+ for (j = 0; j < 4; j++) {
+ mul_m4_v3(obmat, vec_lr[i][j]);
+ }
+ }
+ }
+
+
+ /* the remaining drawing takes place in the view space */
+ glLoadMatrixf(rv3d->viewmat);
+
+ if (is_stereo3d_cameras) {
+ /* draw connecting lines */
+ glPushAttrib(GL_ENABLE_BIT);
+
+ glLineStipple(2, 0xAAAA);
+ glEnable(GL_LINE_STIPPLE);
+
+ glBegin(GL_LINES);
+ glVertex3fv(origin[0]);
+ glVertex3fv(origin[1]);
+ glEnd();
+ glPopAttrib();
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_plane) {
+ float axis_center[3], screen_center[3];
+ float world_plane[4][3];
+ float local_plane[4][3];
+ float offset;
+
+ mid_v3_v3v3(axis_center, origin[0], origin[1]);
+
+ for (i = 0; i < 4; i++) {
+ mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
+ sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
+ }
+
+ mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
+ offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
+
+ for (i = 0; i < 4; i++) {
+ mul_v3_fl(local_plane[i], offset);
+ add_v3_v3(local_plane[i], axis_center);
+ }
+
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ /* camera frame */
+ drawcamera_frame(local_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_convergence_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
+
+ drawcamera_frame(local_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_volume) {
+ float screen_center[3];
+ float near_plane[4][3], far_plane[4][3];
+ float offset;
+ int j;
+
+ for (i = 0; i < 2; i++) {
+ mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
+
+ offset = len_v3v3(screen_center, origin[i]);
+
+ for (j = 0; j < 4; j++) {
+ sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
+ add_v3_v3(near_plane[j], origin[i]);
+
+ sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
+ add_v3_v3(far_plane[j], origin[i]);
+ }
+
+ /* camera frame */
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ drawcamera_frame(near_plane, GL_LINE_LOOP);
+ drawcamera_frame(far_plane, GL_LINE_LOOP);
+ drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_volume_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ if (i == 0)
+ glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
+ else
+ glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
+
+ drawcamera_frame(near_plane, GL_QUADS);
+ drawcamera_frame(far_plane, GL_QUADS);
+ drawcamera_volume(near_plane, far_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+ }
+
+ glPopMatrix();
+}
+
/* flag similar to draw_object() */
static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const short dflag, const unsigned char ob_wire_col[4])
@@ -1757,9 +2053,20 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
float vec[4][3], asp[2], shift[2], scale[3];
int i;
float drawsize;
- const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
+ const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
+ const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_cameras = (ob == scene->camera) &&
+ is_multiview &&
+ is_stereo3d_view &&
+ (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
+ const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
+ is_view && is_multiview &&
+ is_stereo3d_view;
+
/* draw data for movie clip set as active for scene */
if (clip) {
draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
@@ -1785,9 +2092,17 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
cam = ob->data;
- scale[0] = 1.0f / len_v3(ob->obmat[0]);
- scale[1] = 1.0f / len_v3(ob->obmat[1]);
- scale[2] = 1.0f / len_v3(ob->obmat[2]);
+ /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
+ if (is_selection_camera_stereo) {
+ scale[0] = 1.0f;
+ scale[1] = 1.0f;
+ scale[2] = 1.0f;
+ }
+ else {
+ scale[0] = 1.0f / len_v3(ob->obmat[0]);
+ scale[1] = 1.0f / len_v3(ob->obmat[1]);
+ scale[2] = 1.0f / len_v3(ob->obmat[2]);
+ }
BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
asp, shift, &drawsize, vec);
@@ -1796,12 +2111,24 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glDisable(GL_CULL_FACE);
/* camera frame */
- glBegin(GL_LINE_LOOP);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[1]);
- glVertex3fv(vec[2]);
- glVertex3fv(vec[3]);
- glEnd();
+ if (!is_stereo3d_cameras) {
+ /* make sure selection uses the same matrix for camera as the one used while viewing */
+ if (is_selection_camera_stereo) {
+ float obmat[4][4];
+ bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+
+ glPushMatrix();
+ glLoadMatrixf(rv3d->viewmat);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
+ glMultMatrixf(obmat);
+
+ drawcamera_frame(vec, GL_LINE_LOOP);
+ glPopMatrix();
+ }
+ else {
+ drawcamera_frame(vec, GL_LINE_LOOP);
+ }
+ }
if (is_view)
return;
@@ -1809,20 +2136,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
zero_v3(tvec);
/* center point to camera frame */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[1]);
- glVertex3fv(tvec);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[3]);
- glVertex3fv(tvec);
- glVertex3fv(vec[2]);
- glEnd();
-
+ if (!is_stereo3d_cameras)
+ drawcamera_framelines(vec, tvec);
/* arrow on top */
tvec[2] = vec[1][2]; /* copy the depth */
-
/* draw an outline arrow for inactive cameras and filled
* for active cameras. We actually draw both outline+filled
* for active cameras so the wire can be seen side-on */
@@ -1872,14 +2191,17 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glPopMatrix();
}
}
+
+ /* stereo cameras drawing */
+ if (is_stereo3d) {
+ drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
+ }
}
/* flag similar to draw_object() */
static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
Object *UNUSED(ob), int UNUSED(flag))
{
- //Speaker *spk = ob->data;
-
float vec[3];
int i, j;
@@ -1990,9 +2312,9 @@ static void ensure_curve_cache(Scene *scene, Object *object)
* here, we also need to check whether display list is
* empty or not.
*
- * The trick below tries to optimie calls to displist
+ * The trick below tries to optimize calls to displist
* creation for cases curve is empty. Meaning, if the curve
- * is empty (without splies) bevel list would also be empty.
+ * is empty (without splines) bevel list would also be empty.
* And the thing is, render thread always leaves bevel list
* in a proper state. So if bevel list is here and display
* list is not we need to make display list.
@@ -2270,8 +2592,7 @@ static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
- /* skin nodes: draw a red circle around the root
- * node(s) */
+ /* skin nodes: draw a red circle around the root node(s) */
if (data->cd_vskin_offset != -1) {
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
if (vs->flag & MVERT_SKIN_ROOT) {
@@ -2337,7 +2658,6 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
{
BMEdge *eed;
- //unsigned char **cols = userData, *col;
drawDMEdgesSel_userData *data = userData;
unsigned char *col;
@@ -2354,7 +2674,7 @@ static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
else {
col = data->baseCol;
}
- /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
+ /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
if (col[3] == 0)
return DM_DRAW_OPTION_SKIP;
@@ -2751,7 +3071,7 @@ static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *ba
data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
}
- dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
+ dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, 0);
}
static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
@@ -3044,7 +3364,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
}
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
@@ -3082,7 +3402,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
unit->system, B_UNIT_LENGTH, do_split, false);
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
}
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
@@ -3101,17 +3421,15 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
}
- // invert_m4_m4(ob->imat, ob->obmat); // this is already called
-
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
- /* special case, this is useful to show when vertes connected to this edge via a
- * face are being transformed */
+ /* special case, this is useful to show when verts connected to
+ * this edge via a face are being transformed */
BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
@@ -3161,7 +3479,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_normalized_v3v3(no_a, no_b);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3186,7 +3504,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
3, unit->system, B_UNIT_AREA, do_split, false); \
} \
else { \
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area); \
} \
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \
} (void)0
@@ -3304,7 +3622,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_v3v3v3(v1, v2, v3);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
view3d_cached_text_draw_add(fvec, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3335,7 +3653,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(v->co, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3347,7 +3665,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
mid_v3_v3v3(pos, e->v1->co, e->v2->co);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3361,7 +3679,7 @@ static void draw_em_indices(BMEditMesh *em)
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
BM_face_calc_center_mean(f, pos);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3417,7 +3735,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
if (em->bm->selected.last) {
BMEditSelection *ese = em->bm->selected.last;
- /* face is handeled above */
+ /* face is handled above */
#if 0
if (ese->type == BM_FACE) {
efa_act = (BMFace *)ese->data;
@@ -3532,11 +3850,14 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
else if (efa_act) {
/* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active
- * */
- /* col4 is only used by WITH_FREESTYLE, but keeping it here spares some #ifdef's... */
- unsigned char col1[4], col2[4], col3[4], col4[4];
- col1[3] = col2[3] = col4[3] = 0; /* don't draw */
+ * Make all other faces zero alpha except for the active */
+ unsigned char col1[4], col2[4], col3[4];
+#ifdef WITH_FREESTYLE
+ unsigned char col4[4];
+ col4[3] = 0; /* don't draw */
+#endif
+ col1[3] = col2[3] = 0; /* don't draw */
+
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
glEnable(GL_BLEND);
@@ -3550,7 +3871,6 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
glDisable(GL_BLEND);
glDepthMask(1); /* restore write in zbuffer */
-
}
/* here starts all fancy draw-extra over */
@@ -3691,7 +4011,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
#endif
Mesh *me = ob->data;
eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
- int /* totvert,*/ totedge, totface;
+ bool /* no_verts,*/ no_edges, no_faces;
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
const bool is_obact = (ob == OBACT);
int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
@@ -3714,9 +4034,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_wire = OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */
}
- /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
- totedge = dm->getNumEdges(dm);
- totface = dm->getNumTessFaces(dm);
+ /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
+ no_edges = (dm->getNumEdges(dm) == 0);
+ no_faces = (dm->getNumPolys(dm) == 0);
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
@@ -3725,15 +4045,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
draw_bounding_volume(ob, ob->boundtype);
}
- else if ((totface == 0 && totedge == 0) ||
+ else if ((no_faces && no_edges) ||
((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
{
glPointSize(1.5);
dm->drawVerts(dm);
glPointSize(1.0);
}
- else if (dt == OB_WIRE || totface == 0) {
- draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
+ else if ((dt == OB_WIRE) || no_faces) {
+ draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
}
else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
check_object_draw_texture(scene, v3d, dt))
@@ -3775,8 +4095,10 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
else
dm->drawFacesGLSL(dm, GPU_enable_material);
-// if (BKE_bproperty_object_get(ob, "Text"))
-// XXX draw_mesh_text(ob, 1);
+#if 0 /* XXX */
+ if (BKE_bproperty_object_get(ob, "Text"))
+ draw_mesh_text(ob, 1);
+#endif
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -3894,7 +4216,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */
- /* when overriding with render only, don't bother */
+ /* when overriding with render only, don't bother */
(((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0))
{
/* When using wireframe object draw in particle edit mode
@@ -3924,7 +4246,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
}
- dm->drawEdges(dm, (dt == OB_WIRE || totface == 0), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
+ dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
glDepthMask(1);
@@ -3933,7 +4255,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if (is_obact && BKE_paint_select_vert_test(ob)) {
- const int use_depth = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
@@ -3948,7 +4270,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
dm->release(dm);
}
-/* returns 1 if nothing was drawn, for detecting to draw an object center */
+/* returns true if nothing was drawn, for detecting to draw an object center */
static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
@@ -3992,7 +4314,9 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
scene->customdata_mask);
DM_update_materials(finalDM, ob);
- DM_update_materials(cageDM, ob);
+ if (cageDM != finalDM) {
+ DM_update_materials(cageDM, ob);
+ }
if (dt > OB_WIRE) {
const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
@@ -4328,7 +4652,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/**
* Only called by #drawDispList
- * \return 1 when nothing was drawn
+ * \return true when nothing was drawn
*/
static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
@@ -4600,7 +4924,7 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
vec[2] = 2.0f * pixsize;
- vec[0] = vec[1] = 0.0;
+ vec[0] = vec[1] = 0.0f;
mul_qt_v3(state->rot, vec);
if (draw_as == PART_DRAW_AXIS) {
copy_v3_v3(vec2, state->co);
@@ -4683,7 +5007,7 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
if (psys->parent)
mul_m4_v3(psys->parent->obmat, state->co);
- /* create actiual particle data */
+ /* create actual particle data */
if (draw_as == PART_DRAW_BB) {
bb->offset[0] = part->bb_offset[0];
bb->offset[1] = part->bb_offset[1];
@@ -4708,16 +5032,17 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
}
-/* unified drawing of all new particle systems draw types except dupli ob & group */
-/* mostly tries to use vertex arrays for speed */
-
-/* 1. check that everything is ok & updated */
-/* 2. start initializing things */
-/* 3. initialize according to draw type */
-/* 4. allocate drawing data arrays */
-/* 5. start filling the arrays */
-/* 6. draw the arrays */
-/* 7. clean up */
+/* unified drawing of all new particle systems draw types except dupli ob & group
+ * mostly tries to use vertex arrays for speed
+ *
+ * 1. check that everything is ok & updated
+ * 2. start initializing things
+ * 3. initialize according to draw type
+ * 4. allocate drawing data arrays
+ * 5. start filling the arrays
+ * 6. draw the arrays
+ * 7. clean up
+ */
static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Base *base, ParticleSystem *psys,
const char ob_dt, const short dflag)
@@ -4762,6 +5087,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (draw_as == PART_DRAW_NOT)
return;
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+
/* 2. */
sim.scene = scene;
sim.ob = ob;
@@ -4907,7 +5238,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
int create_ndata = 0;
if (!pdd)
- pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData");
+ pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
tot_vec_size *= part->trail_count;
@@ -5010,7 +5341,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
BLI_assert(0);
break;
}
- CLAMP(intensity, 0.f, 1.f);
+ CLAMP(intensity, 0.0f, 1.0f);
weight_to_rgb(ma_col, intensity);
}
}
@@ -5069,8 +5400,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
if (drawn) {
- /* additional things to draw for each particle */
- /* (velocity, size and number) */
+ /* additional things to draw for each particle
+ * (velocity, size and number) */
if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) {
copy_v3_v3(pdd->ved, state.co);
pdd->ved += 3;
@@ -5098,21 +5429,21 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_NUM) {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
}
else {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d", a);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a);
}
}
else {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%.2f", pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health);
}
}
if (numstr[0]) {
- /* in path drawing state.co is the end point */
- /* use worldspace beause object matrix is already applied */
+ /* in path drawing state.co is the end point
+ * use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, state.co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5129,7 +5460,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (draw_as == PART_DRAW_PATH) {
ParticleCacheKey **cache, *path;
- float /* *cd2=NULL, */ /* UNUSED */ *cdata2 = NULL;
+ float *cdata2 = NULL;
/* setup gl flags */
if (1) { //ob_dt > OB_WIRE) {
@@ -5193,11 +5524,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
HairKey *hkey = pa->hair;
glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
-
- // XXX use proper theme color here
-// UI_ThemeColor(TH_NORMAL);
+
+#if 0 /* XXX use proper theme color here */
+ UI_ThemeColor(TH_NORMAL);
+#else
glColor3f(0.58f, 0.67f, 1.0f);
-
+#endif
+
glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
}
}
@@ -5274,22 +5607,22 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100);
glEnable(GL_BLEND);
glBegin(GL_LINES);
- for (i = 1; i < res[0]-1; ++i) {
- float f = interpf(b[0], a[0], (float)i / (float)(res[0]-1));
+ for (i = 1; i < res[0] - 1; ++i) {
+ float f = interpf(b[0], a[0], (float)i / (float)(res[0] - 1));
glVertex3f(f, a[1], a[2]); glVertex3f(f, b[1], a[2]);
glVertex3f(f, b[1], a[2]); glVertex3f(f, b[1], b[2]);
glVertex3f(f, b[1], b[2]); glVertex3f(f, a[1], b[2]);
glVertex3f(f, a[1], b[2]); glVertex3f(f, a[1], a[2]);
}
- for (i = 1; i < res[1]-1; ++i) {
- float f = interpf(b[1], a[1], (float)i / (float)(res[1]-1));
+ for (i = 1; i < res[1] - 1; ++i) {
+ float f = interpf(b[1], a[1], (float)i / (float)(res[1] - 1));
glVertex3f(a[0], f, a[2]); glVertex3f(b[0], f, a[2]);
glVertex3f(b[0], f, a[2]); glVertex3f(b[0], f, b[2]);
glVertex3f(b[0], f, b[2]); glVertex3f(a[0], f, b[2]);
glVertex3f(a[0], f, b[2]); glVertex3f(a[0], f, a[2]);
}
- for (i = 1; i < res[2]-1; ++i) {
- float f = interpf(b[2], a[2], (float)i / (float)(res[2]-1));
+ for (i = 1; i < res[2] - 1; ++i) {
+ float f = interpf(b[2], a[2], (float)i / (float)(res[2] - 1));
glVertex3f(a[0], a[1], f); glVertex3f(b[0], a[1], f);
glVertex3f(b[0], a[1], f); glVertex3f(b[0], b[1], f);
glVertex3f(b[0], b[1], f); glVertex3f(a[0], b[1], f);
@@ -5326,7 +5659,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
-
/* restore & clean up */
if (1) { //ob_dt > OB_WIRE) {
if (part->draw_col == PART_DRAW_COL_MAT)
@@ -5334,9 +5666,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDisable(GL_COLOR_MATERIAL);
}
- if (cdata2)
+ if (cdata2) {
MEM_freeN(cdata2);
- /* cd2 = */ /* UNUSED */ cdata2 = NULL;
+ cdata2 = NULL;
+ }
glLineWidth(1.0f);
@@ -5345,8 +5678,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
float vec_txt[3];
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%i", a);
- /* use worldspace beause object matrix is already applied */
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
+ /* use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5474,7 +5807,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
PTCacheEditPoint *point;
PTCacheEditKey *key;
ParticleEditSettings *pset = PE_settings(scene);
- int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
+ int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0;
int totkeys = 1;
float sel_col[3];
float nosel_col[3];
@@ -5614,7 +5947,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glColor3fv(nosel_col);
/* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
glBegin(GL_POINTS);
- glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co);
+ glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
glEnd();
}
}
@@ -5630,9 +5963,9 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glLineWidth(1.0f);
- glPointSize(1.0);
+ glPointSize(1.0f);
}
-//static void ob_draw_RE_motion(float com[3],float rotscale[3][3],float tw,float th)
+
static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size)
{
float tr[3][3];
@@ -6036,7 +6369,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
Nurb *nu;
BPoint *bp, *bp1;
int a, b, ofs, index;
- Curve *cu = (Curve *)ob->data;
+ Curve *cu = ob->data;
index = 0;
nu = nurb;
@@ -6396,7 +6729,7 @@ static void draw_empty_sphere(float size)
static GLuint displist = 0;
if (displist == 0) {
- GLUquadricObj *qobj;
+ GLUquadricObj *qobj;
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
@@ -6427,16 +6760,13 @@ static void draw_empty_sphere(float size)
/* draw a cone for use as an empty drawtype */
static void draw_empty_cone(float size)
{
- float cent = 0;
- float radius;
+ const float radius = size;
+
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
glPushMatrix();
- radius = size;
- glTranslatef(cent, cent, cent);
glScalef(radius, size * 2.0f, radius);
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
@@ -6449,7 +6779,7 @@ static void draw_empty_cone(float size)
static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
{
float vec[3], vx[3], vy[3];
- const float tot_inv = (1.0f / (float)CIRCLE_RESOL);
+ const float tot_inv = 1.0f / (float)CIRCLE_RESOL;
int a;
bool inverse = false;
float x, y, fac;
@@ -6513,8 +6843,7 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
}
/* draws a circle on x-z plane given the scaling of the circle, assuming that
- * all required matrices have been set (used for drawing empties)
- */
+ * all required matrices have been set (used for drawing empties) */
static void drawcircle_size(float size)
{
float x, y;
@@ -6522,7 +6851,7 @@ static void drawcircle_size(float size)
glBegin(GL_LINE_LOOP);
- /* coordinates are: cos(degrees * 11.25) = x, sin(degrees*11.25) = y, 0.0f = z */
+ /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */
for (degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
x = cosval[degrees];
y = sinval[degrees];
@@ -6666,31 +6995,23 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
PartDeflect *pd = ob->pd;
float imat[4][4], tmat[4][4];
float vec[3] = {0.0, 0.0, 0.0};
- float size;
-
/* scale size of circle etc with the empty drawsize */
- if (ob->type == OB_EMPTY) size = ob->empty_drawsize;
- else size = 1.0;
+ const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
/* calculus here, is reused in PFIELD_FORCE */
invert_m4_m4(imat, rv3d->viewmatob);
-// normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
-// normalize_v3(imat[1]);
+#if 0
+ normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
+ normalize_v3(imat[1]);
+#endif
if (pd->forcefield == PFIELD_WIND) {
- float force_val;
+ float force_val = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
-
unit_m4(tmat);
force_val *= 0.1f;
drawcircball(GL_LINE_LOOP, vec, size, tmat);
@@ -6704,14 +7025,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
}
else if (pd->forcefield == PFIELD_FORCE) {
- float ffall_val;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- {
- ffall_val = pd->f_power;
- }
+ float ffall_val = pd->f_power;
if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
drawcircball(GL_LINE_LOOP, vec, size, imat);
@@ -6721,20 +7035,9 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
drawcircball(GL_LINE_LOOP, vec, size * 2.0f, imat);
}
else if (pd->forcefield == PFIELD_VORTEX) {
- float /*ffall_val,*/ force_val;
+ float force_val = pd->f_strength;
unit_m4(tmat);
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- // ffall_val = pd->f_power;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f);
@@ -6752,25 +7055,19 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
Curve *cu = ob->data;
if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
- float mindist, guidevec1[4], guidevec2[3];
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- mindist = pd->f_strength;
- }
+ float guidevec1[4], guidevec2[3];
+ float mindist = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- /*path end*/
+ /* path end */
setlinestyle(3);
where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
- /*path beginning*/
+ /* path beginning */
setlinestyle(0);
where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
@@ -6841,19 +7138,31 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
setlinestyle(0);
}
-static void draw_box(float vec[8][3])
+static void draw_box(float vec[8][3], bool solid)
{
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
- glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
- glVertex3fv(vec[7]); glVertex3fv(vec[4]);
- glEnd();
+ if (!solid) {
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[4]);
+ glEnd();
- glBegin(GL_LINES);
- glVertex3fv(vec[1]); glVertex3fv(vec[5]);
- glVertex3fv(vec[2]); glVertex3fv(vec[6]);
- glVertex3fv(vec[3]); glVertex3fv(vec[7]);
- glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]);
+ glVertex3fv(vec[2]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]);
+ glEnd();
+ }
+ else {
+ glBegin(GL_QUADS);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[6]); glVertex3fv(vec[5]); glVertex3fv(vec[4]);
+ glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[1]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[2]); glVertex3fv(vec[6]); glVertex3fv(vec[7]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]); glVertex3fv(vec[4]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]); glVertex3fv(vec[6]); glVertex3fv(vec[2]);
+ glEnd();
+ }
}
static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
@@ -6947,7 +7256,7 @@ static void draw_bounding_volume(Object *ob, char type)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
}
else {
draw_bb_quadric(bb, type, true);
@@ -6955,7 +7264,7 @@ static void draw_bounding_volume(Object *ob, char type)
}
else {
if (type == OB_BOUND_BOX)
- draw_box(bb->vec);
+ draw_box(bb->vec, false);
else
draw_bb_quadric(bb, type, false);
}
@@ -6991,7 +7300,7 @@ static void drawtexspace(Object *ob)
setlinestyle(2);
- draw_box(vec);
+ draw_box(vec, false);
setlinestyle(0);
}
@@ -7178,7 +7487,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
else {
if (ob->flag & OB_FROMGROUP) {
if (base->flag & (SELECT + BA_WAS_SEL)) {
- /* uses darker active color for non-active + selected*/
+ /* uses darker active color for non-active + selected */
theme_id = TH_GROUP_ACTIVE;
if (scene->basact != base) {
@@ -7232,8 +7541,11 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob)
v3d->defmaterial->preview = NULL;
}
/* first time users */
- if (v3d->matcap_icon == 0)
+ if (v3d->matcap_icon < ICON_MATCAP_01 ||
+ v3d->matcap_icon > ICON_MATCAP_24)
+ {
v3d->matcap_icon = ICON_MATCAP_01;
+ }
if (v3d->defmaterial->preview == NULL)
v3d->defmaterial->preview = UI_icon_to_preview(v3d->matcap_icon);
@@ -7265,7 +7577,7 @@ static void draw_rigidbody_shape(Object *ob)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
break;
case RB_SHAPE_SPHERE:
draw_bb_quadric(bb, OB_BOUND_SPHERE, true);
@@ -7302,7 +7614,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
const bool is_picking = (G.f & G_PICKSEL) != 0;
const bool has_particles = (ob->particlesystem.first != NULL);
- bool particle_skip_object = false; /* Draw particles but not their emitter object. */
+ bool skip_object = false; /* Draw particles but not their emitter object. */
+ SmokeModifierData *smd = NULL;
if (ob != scene->obedit) {
if (ob->restrictflag & OB_RESTRICT_VIEW)
@@ -7326,17 +7639,37 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode == OB_MODE_OBJECT) {
ParticleSystem *psys;
- particle_skip_object = render_override;
+ skip_object = render_override;
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
/* Once we have found a psys which renders its emitter object, we are done. */
if (psys->part->draw & PART_DRAW_EMITTER) {
- particle_skip_object = false;
+ skip_object = false;
break;
}
}
}
}
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
+ smd = (SmokeModifierData *)md;
+
+ if (smd->domain) {
+ if (!v3d->transp && (dflag & DRAW_PICKING) == 0) {
+ if (!v3d->xray && !(ob->dtx & OB_DRAWXRAY)) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ return;
+ }
+ else if (v3d->xray) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag);
+ return;
+ }
+ }
+ }
+ }
+
+
/* xray delay? */
if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
/* don't do xray in particle mode, need the z-buffer */
@@ -7435,13 +7768,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (dt >= OB_BOUNDBOX) {
dtx = ob->dtx;
if (ob->mode & OB_MODE_EDIT) {
- // the only 2 extra drawtypes alowed in editmode
+ /* the only 2 extra drawtypes alowed in editmode */
dtx = dtx & (OB_DRAWWIRE | OB_TEXSPACE);
}
-
}
- if (!particle_skip_object) {
+ if (!skip_object) {
/* draw outline for selected objects, mesh does itself */
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) {
@@ -7496,9 +7828,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
-
-//XXX old animsys if (cu->path)
-// curve_draw_speed(scene, ob);
}
break;
case OB_MBALL:
@@ -7663,12 +7992,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* draw code for smoke */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- // draw collision objects
- if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
+ if (smd) {
#if 0
+ /* draw collision objects */
+ if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
SmokeCollSettings *scs = smd->coll;
if (scs->points) {
size_t i;
@@ -7695,30 +8022,30 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
if (col) cpack(col);
-
}
-#endif
}
+#endif
/* only draw domains */
if (smd->domain) {
SmokeDomainSettings *sds = smd->domain;
- float p0[3], p1[3], viewnormal[3];
- BoundBox bb;
+ float viewnormal[3];
glLoadMatrixf(rv3d->viewmat);
glMultMatrixf(ob->obmat);
/* draw adaptive domain bounds */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) {
+ float p0[3], p1[3];
+ BoundBox bb;
/* draw domain max bounds */
VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec);
+ draw_box(bb.vec, false);
- /* draw base resolution bounds */
#if 0
+ /* draw base resolution bounds */
BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);
#endif
@@ -7726,16 +8053,16 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* don't show smoke before simulation starts, this could be made an option in the future */
if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
+ float p0[3], p1[3];
- // get view vector
- copy_v3_v3(viewnormal, rv3d->viewinv[2]);
+ /* get view vector */
invert_m4_m4(ob->imat, ob->obmat);
- mul_mat3_m4_v3(ob->imat, viewnormal);
+ mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
normalize_v3(viewnormal);
/* set dynamic boundaries to draw the volume
- * also scale cube to global space to equalize volume slicing on all axises
- * (its scaled back before drawing) */
+ * also scale cube to global space to equalize volume slicing on all axes
+ * (it's scaled back before drawing) */
p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
@@ -7819,7 +8146,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
view3d_cached_text_draw_add(zero, ob->id.name + 2, strlen(ob->id.name + 2), 10, 0, ob_wire_col);
}
}
- /*if (dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/
if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
draw_wire_extra(scene, rv3d, ob, ob_wire_col);
@@ -7935,7 +8261,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
/* special case for object solver and follow track constraints because they don't fill
* constraint targets properly (design limitation -- scene is needed for their target
- * but it can't be accessed from get_targets callvack) */
+ * but it can't be accessed from get_targets callback) */
Object *camob = NULL;
@@ -7960,7 +8286,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
else {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
ListBase targets = {NULL, NULL};
@@ -8192,7 +8518,7 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- Mesh *me = (Mesh *)ob->data;
+ Mesh *me = ob->data;
glColor3ub(0, 0, 0);
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
index 6113bfd4143..46320ba6763 100644
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -29,28 +29,21 @@
* \ingroup spview3d
*/
-#include "MEM_guardedalloc.h"
-
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_object_types.h"
-#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BKE_effect.h"
-#include "BKE_global.h"
-#include "BKE_modifier.h"
#include "view3d_intern.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
-#include "UI_resources.h"
static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
{
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index a220e1e39b0..d6691f431dd 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -48,8 +48,6 @@
#include "GPU_extensions.h"
-#include "ED_mesh.h"
-
#include "view3d_intern.h" // own include
struct GPUTexture;
@@ -107,7 +105,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
float cor[3] = {1.0f, 1.0f, 1.0f};
int gl_depth = 0, gl_blend = 0;
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
+ const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
/* draw slices of smoke is adapted from c++ code authored
* by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
@@ -137,76 +135,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
unsigned char *spec_data;
float *spec_pixels;
GPUTexture *tex_spec;
-
- /* Fragment program to calculate the view3d of smoke */
- /* using 4 textures, density, shadow, flame and flame spectrum */
- const char *shader_basic =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 temp, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, temp.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, darkness.r;\n"
- "MUL temp.g, temp.g, darkness.g;\n"
- "MUL temp.b, temp.b, darkness.b;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- /* color shader */
- const char *shader_color =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* unpremultiply volume texture */
- "RCP value.r, temp.a;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 value.r, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, value.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- GLuint prog;
-
-
+ GPUProgram *smoke_program;
+ int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE;
float size[3];
if (!tex) {
@@ -323,8 +253,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
+ glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
/* find cube vertex that is closest to the viewer */
@@ -351,24 +280,17 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
// printf("i: %d\n", i);
// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
- if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
- glGenProgramsARB(1, &prog);
-
- glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
- /* set shader */
- if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
- else
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
+ smoke_program = GPU_shader_get_builtin_program(progtype);
+ if (smoke_program) {
+ GPU_program_bind(smoke_program);
/* cell spacing */
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
+ GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0);
/* custom parameter for smoke style (higher = thicker) */
if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0);
else
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
}
else
printf("Your gfx card does not support 3D View smoke drawing.\n");
@@ -448,7 +370,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -468,7 +390,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -501,10 +423,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
free(spec_data);
free(spec_pixels);
- if (GLEW_ARB_fragment_program) {
- glDisable(GL_FRAGMENT_PROGRAM_ARB);
- glDeleteProgramsARB(1, &prog);
- }
+ if (smoke_program)
+ GPU_program_unbind(smoke_program);
MEM_freeN(points);
@@ -516,8 +436,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
if (gl_depth) {
glEnable(GL_DEPTH_TEST);
}
-
- glDepthMask(GL_TRUE);
}
#ifdef SMOKE_DEBUG_VELOCITY
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 35fb2bce115..096d9e8a40a 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -74,6 +74,8 @@
# include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
@@ -266,7 +268,7 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d)
}
#endif
-static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
+void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
@@ -297,7 +299,7 @@ void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiondata)
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
}
}
else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
@@ -344,7 +346,13 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
-
+
+ /* stereo */
+ v3d->stereo3d_camera = STEREO_3D_ID;
+ v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
+ v3d->stereo3d_convergence_alpha = 0.15f;
+ v3d->stereo3d_volume_alpha = 0.05f;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for view3d");
@@ -563,7 +571,7 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
if (rv3d->gpuoffscreen) {
GPU_offscreen_free(rv3d->gpuoffscreen);
@@ -925,7 +933,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
(ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
(scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ BKE_scene_use_new_shading_nodes(scene))) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -948,7 +957,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_LIGHTING:
if ((v3d->drawtype == OB_MATERIAL) ||
- (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
+ (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -1005,7 +1015,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case NC_GPENCIL:
- if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
+ if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
}
break;
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 88f43ab340f..1f8a69adba0 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -68,7 +68,6 @@
#include "RNA_access.h"
#include "ED_armature.h"
-#include "ED_gpencil.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -200,7 +199,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
bool has_skinradius = false;
PointerRNA data_ptr;
- fill_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
+ copy_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
/* make sure we got storage */
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 58ef9184dd0..fb0f437884a 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -50,11 +50,13 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_endian_switch.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -99,6 +101,11 @@
#include "view3d_intern.h" /* own include */
+/* prototypes */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname);
+
/* handy utility for drawing shapes in the viewport for arbitrary code.
* could add lines and points too */
// #define DEBUG_DRAW
@@ -207,7 +214,7 @@ void ED_view3d_clipping_enable(void)
}
}
-static bool view3d_clipping_test(const float co[3], float clip[6][4])
+static bool view3d_clipping_test(const float co[3], const float clip[6][4])
{
if (plane_point_side_v3(clip[0], co) > 0.0f)
if (plane_point_side_v3(clip[1], co) > 0.0f)
@@ -220,7 +227,7 @@ static bool view3d_clipping_test(const float co[3], float clip[6][4])
/* for 'local' ED_view3d_clipping_local must run first
* then all comparisons can be done in localspace */
-bool ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local)
+bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
}
@@ -465,7 +472,7 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
}
-static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
+static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
{
float grid, grid_scale;
unsigned char col_grid[3];
@@ -477,7 +484,8 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
grid = gridlines * grid_scale;
- glDepthMask(GL_FALSE);
+ if (!write_depth)
+ glDepthMask(GL_FALSE);
UI_GetThemeColor3ubv(TH_GRID, col_grid);
@@ -650,7 +658,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
- if (rv3d->rot_angle != 0.f) {
+ if (rv3d->rot_angle != 0.0f) {
/* -- draw rotation axis -- */
float scaled_axis[3];
const float scale = rv3d->dist;
@@ -658,19 +666,21 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glBegin(GL_LINE_STRIP);
- color[3] = 0.f; /* more transparent toward the ends */
+ color[3] = 0.0f; /* more transparent toward the ends */
glColor4fv(color);
add_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
- // color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
- // ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
+#if 0
+ color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
+ /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
+#endif
color[3] = 0.5f; /* more opaque toward the center */
glColor4fv(color);
glVertex3fv(o);
- color[3] = 0.f;
+ color[3] = 0.0f;
glColor4fv(color);
sub_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
@@ -681,14 +691,14 @@ static void draw_rotation_guide(RegionView3D *rv3d)
#define ROT_AXIS_DETAIL 13
const float s = 0.05f * scale;
- const float step = 2.f * (float)(M_PI / ROT_AXIS_DETAIL);
+ const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
float angle;
int i;
float q[4]; /* rotate ring so it's perpendicular to axis */
const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
if (!upright) {
- const float up[3] = {0.f, 0.f, 1.f};
+ const float up[3] = {0.0f, 0.0f, 1.0f};
float vis_angle, vis_axis[3];
cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
@@ -699,7 +709,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
color[3] = 0.25f; /* somewhat faint */
glColor4fv(color);
glBegin(GL_LINE_LOOP);
- for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
if (!upright) {
@@ -725,12 +735,12 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glVertex3fv(o);
glEnd();
- /* find screen coordinates for rotation center, then draw pretty icon */
#if 0
+ /* find screen coordinates for rotation center, then draw pretty icon */
mul_m4_v3(rv3d->persinv, rot_center);
UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
-#endif
/* ^^ just playing around, does not work */
+#endif
glDisable(GL_BLEND);
glDisable(GL_POINT_SMOOTH);
@@ -949,8 +959,9 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
}
-static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift, const bool no_zoom)
+static void view3d_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
rctf rect_view, rect_camera;
@@ -983,7 +994,9 @@ static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionV
r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
}
-void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2])
+void ED_view3d_calc_camera_border_size(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ float r_size[2])
{
rctf viewborder;
@@ -992,8 +1005,9 @@ void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, R
r_size[1] = BLI_rctf_size_y(&viewborder);
}
-void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift)
+void ED_view3d_calc_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift)
{
view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
}
@@ -1314,12 +1328,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
/* do nothing */
}
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
- v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
- else if (scene->obedit && v3d->drawtype > OB_WIRE &&
- (v3d->flag & V3D_ZBUF_SELECT))
+ else if (scene->obedit &&
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
@@ -1441,14 +1455,23 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h,
glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
}
-void view3d_validate_backbuf(ViewContext *vc)
+void ED_view3d_backbuf_validate(ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF)
backdrawview3d(vc->scene, vc->ar, vc->v3d);
}
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
+int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
+{
+ return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
+}
+
/* samples a single pixel (copied from vpaint) */
-unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
+unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
{
unsigned int col;
@@ -1456,7 +1479,7 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
return 0;
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
@@ -1469,7 +1492,7 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
}
/* reads full rect, converts indices */
-ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+ImBuf *ED_view3d_backbuf_read(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
{
unsigned int *dr, *rd;
struct ImBuf *ibuf, *ibuf1;
@@ -1477,17 +1500,18 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
short xminc, yminc, xmaxc, ymaxc, xs, ys;
/* clip */
- if (xmin < 0) xminc = 0; else xminc = xmin;
- if (xmax >= vc->ar->winx) xmaxc = vc->ar->winx - 1; else xmaxc = xmax;
- if (xminc > xmaxc) return NULL;
+ xminc = max_ii(xmin, 0);
+ yminc = max_ii(ymin, 0);
+ xmaxc = min_ii(xmax, vc->ar->winx - 1);
+ ymaxc = min_ii(ymax, vc->ar->winy - 1);
+
+ if (UNLIKELY((xminc > xmaxc) || (yminc > ymaxc))) {
+ return NULL;
+ }
- if (ymin < 0) yminc = 0; else yminc = ymin;
- if (ymax >= vc->ar->winy) ymaxc = vc->ar->winy - 1; else ymaxc = ymax;
- if (yminc > ymaxc) return NULL;
-
ibuf = IMB_allocImBuf((xmaxc - xminc + 1), (ymaxc - yminc + 1), 32, IB_rect);
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
view3d_opengl_read_pixels(vc->ar,
xminc, yminc,
@@ -1527,23 +1551,21 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
}
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
-unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *r_dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index))
+unsigned int ED_view3d_backbuf_sample_rect(
+ ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist)
{
struct ImBuf *buf;
- unsigned int *bufmin, *bufmax, *tbuf;
+ const unsigned int *bufmin, *bufmax, *tbuf;
int minx, miny;
int a, b, rc, nr, amount, dirvec[4][2];
- int distance = 0;
unsigned int index = 0;
- bool indexok = false;
amount = (size - 1) / 2;
minx = mval[0] - (amount + 1);
miny = mval[1] - (amount + 1);
- buf = view3d_read_backbuf(vc, minx, miny, minx + size - 1, miny + size - 1);
+ buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
if (!buf) return 0;
rc = 0;
@@ -1561,21 +1583,19 @@ unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int
for (nr = 1; nr <= size; nr++) {
for (a = 0; a < 2; a++) {
- for (b = 0; b < nr; b++, distance++) {
- if (*tbuf && *tbuf >= min && *tbuf < max) { /* we got a hit */
- if (strict) {
- indexok = indextest(handle, *tbuf - min + 1);
- if (indexok) {
- *r_dist = sqrtf((float)distance);
- index = *tbuf - min + 1;
- goto exit;
- }
- }
- else {
- *r_dist = sqrtf((float)distance); /* XXX, this distance is wrong - */
- index = *tbuf - min + 1; /* messy yah, but indices start at 1 */
- goto exit;
- }
+ for (b = 0; b < nr; b++) {
+ if (*tbuf && *tbuf >= min && *tbuf < max) {
+ /* we got a hit */
+
+ /* get x,y pixel coords from the offset
+ * (manhatten distance in keeping with other screen-based selection) */
+ *r_dist = (float)(
+ abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
+ abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
+
+ /* indices start at 1 here */
+ index = (*tbuf - min) + 1;
+ goto exit;
}
tbuf += (dirvec[rc][0] + dirvec[rc][1]);
@@ -1597,6 +1617,26 @@ exit:
/* ************************************************************* */
+static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+{
+ if ((ima->flag & IMA_IS_STEREO)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
const bool do_foreground, const bool do_camera_frame)
{
@@ -1620,6 +1660,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
void *lock;
+ rctf clip_rect;
Image *ima = NULL;
MovieClip *clip = NULL;
@@ -1639,6 +1680,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ibuf = NULL; /* frame is out of range, dont show */
}
else {
+ view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
releaseibuf = ibuf;
}
@@ -1782,8 +1824,12 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
}
/* complete clip? */
+ BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
+ if (bgpic->rotation) {
+ BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
+ }
- if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) {
+ if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
@@ -1830,9 +1876,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ED_region_pixelspace(ar);
glTranslatef(centx, centy, 0.0);
- if (rv3d->persp != RV3D_CAMOB) {
- glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
- }
+ glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
if (bgpic->flag & V3D_BGPIC_FLIP_X) {
zoomx *= -1.0f;
@@ -2044,7 +2088,7 @@ static void draw_dupli_objects_color(
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
// BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
- apply_data = duplilist_apply(base->object, lb);
+ apply_data = duplilist_apply(base->object, scene, lb);
dob = dupli_step(lb->first);
if (dob) dob_next = dupli_step(dob->next);
@@ -2479,13 +2523,14 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object
}
}
-static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
+static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
{
ListBase shadows;
View3DShadow *shadow;
Scene *sce_iter;
Base *base;
Object *ob;
+ World *world = scene->world;
SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
BLI_listbase_clear(&shadows);
@@ -2541,7 +2586,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
ED_view3d_draw_offscreen(
scene, v3d, &ar, winsize, winsize, viewmat, winmat,
false, false, true,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
GPU_lamp_shadow_buffer_unbind(shadow->lamp);
v3d->drawtype = drawtype;
@@ -2550,11 +2595,19 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
}
BLI_freelistN(&shadows);
+
+ /* update world values */
+ if (world) {
+ GPU_mist_update_enable(world->mode & WO_MIST);
+ GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
+ GPU_horizon_update_color(&world->horr);
+ GPU_ambient_update_color(&world->ambr);
+ }
}
/* *********************** customdata **************** */
-CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
+CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
{
CustomDataMask mask = 0;
@@ -2580,16 +2633,16 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
}
/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
+CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
{
- Scene *scene = screen->scene;
+ const Scene *scene = screen->scene;
CustomDataMask mask = CD_MASK_BAREMESH;
- ScrArea *sa;
+ const ScrArea *sa;
/* check if we need tfaces & mcols due to view mode */
for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_VIEW3D) {
- mask |= ED_view3d_datamask(scene, (View3D *)sa->spacedata.first);
+ mask |= ED_view3d_datamask(scene, sa->spacedata.first);
}
}
@@ -2674,7 +2727,7 @@ static void view3d_draw_objects(
const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
/* only draw grids after in solid modes, else it hovers over mesh wires */
- const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE);
+ const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx;
bool do_composite_xray = false;
bool xrayclear = true;
@@ -2723,8 +2776,8 @@ static void view3d_draw_objects(
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(rv3d->viewmat);
}
- else {
- drawfloor(scene, v3d, grid_unit);
+ else if (!draw_grids_after) {
+ drawfloor(scene, v3d, grid_unit, true);
}
}
@@ -2802,7 +2855,7 @@ static void view3d_draw_objects(
/* perspective floor goes last to use scene depth and avoid writing to depth buffer */
if (draw_grids_after) {
- drawfloor(scene, v3d, grid_unit);
+ drawfloor(scene, v3d, grid_unit, false);
}
/* must be before xray draw which clears the depth buffer */
@@ -2873,7 +2926,7 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
{
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
+ gpu_update_lamps_shadows_world(scene, v3d);
}
/*
@@ -2887,21 +2940,41 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
if (glsl) {
RegionView3D *rv3d = ar->regiondata;
GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
+ bool material_not_bound;
/* calculate full shader for background */
GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
+ material_not_bound = !GPU_material_bound(gpumat);
+
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glShadeModel(GL_SMOOTH);
- glBegin(GL_QUADS);
+ glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
- glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
+ glVertex3f(1.0, 1.0, 1.0);
glEnd();
glShadeModel(GL_FLAT);
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
GPU_material_unbind(gpumat);
glDepthFunc(GL_LEQUAL);
@@ -3079,7 +3152,8 @@ void ED_view3d_draw_offscreen(
float viewmat[4][4], float winmat[4][4],
bool do_bgpic, bool do_sky, bool is_persp,
GPUOffScreen *ofs,
- GPUFX *fx, GPUFXSettings *fx_settings)
+ GPUFX *fx, GPUFXSettings *fx_settings,
+ const char *viewname)
{
struct bThemeState theme_state;
int bwinx, bwiny;
@@ -3114,11 +3188,24 @@ void ED_view3d_draw_offscreen(
}
/* setup view matrices before fx or unbinding the offscreen buffers will cause issues */
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ 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_area_setup_view(scene, v3d, ar, viewmat, winmat);
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag && fx) {
+ GPUSSAOSettings *ssao = NULL;
+
+ if (v3d->drawtype < OB_SOLID) {
+ ssao = v3d->fx_settings.ssao;
+ v3d->fx_settings.ssao = NULL;
+ }
+
do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
+
+ if (ssao)
+ v3d->fx_settings.ssao = ssao;
}
/* clear opengl buffers */
@@ -3168,13 +3255,16 @@ void ED_view3d_draw_offscreen(
/* utility func for ED_view3d_draw_offscreen */
ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256])
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
ImBuf *ibuf;
GPUOffScreen *ofs;
bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD);
+ if (UNLIKELY(v3d == NULL))
+ return NULL;
+
/* state changes make normal drawing go weird otherwise */
glPushAttrib(GL_LIGHTING_BIT);
@@ -3193,13 +3283,14 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
CameraParams params;
GPUFXSettings fx_settings = {NULL};
- Object *camera = v3d->camera;
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_params_init(&params);
/* fallback for non camera objects */
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3208,13 +3299,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, params.winmat,
draw_background, draw_sky, !params.is_ortho,
- ofs, NULL, &fx_settings);
+ ofs, NULL, &fx_settings, viewname);
}
else {
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, NULL,
draw_background, draw_sky, true,
- ofs, NULL, NULL);
+ ofs, NULL, NULL, viewname);
}
/* read in pixels & stamp */
@@ -3239,7 +3330,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
/* creates own 3d views, used by the sequencer */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256])
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode,
+ const char *viewname, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -3269,9 +3361,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
{
CameraParams params;
+ Object *camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, v3d.camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3285,7 +3379,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
- draw_background, alpha_mode, err_out);
+ draw_background, alpha_mode, viewname, err_out);
// seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
}
@@ -3490,6 +3584,104 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A
ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color);
}
+static bool view3d_stereo3d_active(const bContext *C, 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)
+ return false;
+
+ 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)
+ return false;
+
+ return BKE_scene_multiview_is_stereo3d(&scene->r);
+ }
+
+ return true;
+}
+
+/* setup the view and win matrices for the multiview cameras
+ *
+ * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
+ * we have no winmatrix (i.e., projection matrix) defined at that time.
+ * Since the camera and the camera shift are needed for the winmat calculation
+ * we do a small hack to replace it temporarily so we don't need to change the
+ * view3d)main_area_setup_view() code to account for that.
+ */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
+{
+ bool is_left;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ const char *viewname;
+
+ /* show only left or right camera */
+ if (v3d->stereo3d_camera != STEREO_3D_ID)
+ v3d->multiview_eye = v3d->stereo3d_camera;
+
+ is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+ viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
+
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ Camera *data;
+ float viewmat[4][4];
+ float shiftx;
+
+ data = (Camera *)v3d->camera->data;
+ shiftx = data->shiftx;
+
+ BLI_lock_thread(LOCK_VIEW3D);
+ 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_area_setup_view(scene, v3d, ar, viewmat, NULL);
+
+ data->shiftx = shiftx;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *view_ob = v3d->camera;
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
+
+ BLI_lock_thread(LOCK_VIEW3D);
+ v3d->camera = camera;
+
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
+
+ v3d->camera = view_ob;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+}
+
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname)
+{
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ float viewmat[4][4];
+ const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
+
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ }
+ 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_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ }
+}
+
#ifdef WITH_GAMEENGINE
static void update_lods(Scene *scene, float camera_pos[3])
{
@@ -3515,16 +3707,19 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
-
+ gpu_update_lamps_shadows_world(scene, v3d);
+
/* reset default OpenGL lights if needed (i.e. after preferences have been altered) */
if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) {
rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE;
GPU_default_lights();
}
- /* setup view matrices */
- view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ /* setup the view matrix */
+ if (view3d_stereo3d_active(C, scene, v3d, rv3d))
+ view3d_stereo3d_setup(scene, v3d, ar);
+ else
+ view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
#ifdef WITH_GAMEENGINE
@@ -3537,7 +3732,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
#endif
/* framebuffer fx needed, we need to draw offscreen first */
- if (v3d->fx_settings.fx_flag) {
+ if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) {
GPUFXSettings fx_settings;
BKE_screen_gpu_fx_validate(&v3d->fx_settings);
fx_settings = v3d->fx_settings;
@@ -3549,6 +3744,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
else {
fx_settings.dof = NULL;
}
+
do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings);
}
@@ -3606,7 +3802,7 @@ static bool is_cursor_visible(Scene *scene)
else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
const Paint *p = BKE_paint_get_active(scene);
- if (p && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
+ if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
return true;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 51915e05a9e..d38de4a426e 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -28,7 +28,6 @@
* \ingroup spview3d
*/
-
#include <string.h>
#include <stdio.h>
#include <math.h>
@@ -38,7 +37,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_camera_types.h"
#include "MEM_guardedalloc.h"
@@ -75,7 +73,6 @@
#include "ED_transform.h"
#include "ED_mesh.h"
#include "ED_view3d.h"
-#include "ED_sculpt.h"
#include "UI_resources.h"
@@ -83,7 +80,7 @@
#include "view3d_intern.h" /* own include */
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d)
+bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
}
@@ -103,7 +100,7 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
/* ********************** view3d_edit: view manipulations ********************* */
-bool ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
+bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) &&
(v3d->camera->id.lib == NULL) &&
@@ -520,6 +517,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
typedef struct ViewOpsData {
/* context pointers (assigned by viewops_data_alloc) */
+ Scene *scene;
ScrArea *sa;
ARegion *ar;
View3D *v3d;
@@ -592,6 +590,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
+ vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
vod->ar = CTX_wm_region(C);
vod->v3d = vod->sa->spacedata.first;
@@ -1313,7 +1312,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->cancel = viewrotate_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/** \name NDOF Utility Functions
@@ -2056,7 +2055,7 @@ void VIEW3D_OT_move(wmOperatorType *ot)
ot->cancel = viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/* ************************ viewzoom ******************************** */
@@ -2096,16 +2095,63 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
}
-static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
+static void view_zoom_mouseloc_camera(
+ Scene *scene, View3D *v3d,
+ ARegion *ar, float dfac, int mx, int my)
{
RegionView3D *rv3d = ar->regiondata;
+ const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+ const float zoomfac_new = CLAMPIS(zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
+ const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
+
+
+ if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ float zoomfac_px;
+ rctf camera_frame_old;
+ rctf camera_frame_new;
+
+ const float pt_src[2] = {mx, my};
+ float pt_dst[2];
+ float delta_px[2];
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false);
+ BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin);
+
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false);
+ BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin);
+
+ BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
+ sub_v2_v2v2(delta_px, pt_dst, pt_src);
+
+ /* translate the camera offset using pixel space delta
+ * mapped back to the camera (same logic as panning in camera view) */
+ zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
+
+ rv3d->camdx += delta_px[0] / (ar->winx * zoomfac_px);
+ rv3d->camdy += delta_px[1] / (ar->winy * zoomfac_px);
+ CLAMP(rv3d->camdx, -1.0f, 1.0f);
+ CLAMP(rv3d->camdy, -1.0f, 1.0f);
+ }
+ else {
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+ }
+}
+
+static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ const float dist_new = rv3d->dist * dfac;
if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
float dvec[3];
float tvec[3];
float tpos[3];
float mval_f[2];
- float new_dist;
+
float zfac;
negate_v3_v3(tpos, rv3d->ofs);
@@ -2122,105 +2168,133 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
negate_v3(tvec);
/* Offset to target position and dolly */
- new_dist = rv3d->dist * dfac;
-
copy_v3_v3(rv3d->ofs, tvec);
- rv3d->dist = new_dist;
+ rv3d->dist = dist_new;
/* Calculate final offset */
madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
}
else {
- rv3d->dist *= dfac;
+ rv3d->dist = dist_new;
}
}
-
-static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzoom, const short zoom_invert)
+static float viewzoom_scale_value(
+ const rcti *winrct,
+ const short viewzoom,
+ const bool zoom_invert, const bool zoom_invert_force,
+ const int xy[2], const int xy_orig[2],
+ const float val, const float val_orig,
+ double *r_timer_lastdraw)
{
- float zfac = 1.0;
- bool use_cam_zoom;
- float dist_range[2];
-
- use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d));
-
- ED_view3d_dist_range_get(vod->v3d, dist_range);
-
- if (use_cam_zoom) {
- float delta;
- delta = (xy[0] - vod->origx + xy[1] - vod->origy) / 10.0f;
- vod->rv3d->camzoom = vod->camzoom_prev + (zoom_invert ? -delta : delta);
-
- CLAMP(vod->rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
- }
+ float zfac;
if (viewzoom == USER_ZOOM_CONT) {
double time = PIL_check_seconds_timer();
- float time_step = (float)(time - vod->timer_lastdraw);
+ float time_step = (float)(time - *r_timer_lastdraw);
float fac;
if (U.uiflag & USER_ZOOM_HORIZ) {
- fac = (float)(vod->origx - xy[0]);
+ fac = (float)(xy_orig[0] - xy[0]);
}
else {
- fac = (float)(vod->origy - xy[1]);
+ fac = (float)(xy_orig[1] - xy[1]);
}
- if (zoom_invert) {
+ if (zoom_invert != zoom_invert_force) {
fac = -fac;
}
/* oldstyle zoom */
zfac = 1.0f + ((fac / 20.0f) * time_step);
- vod->timer_lastdraw = time;
+ *r_timer_lastdraw = time;
}
else if (viewzoom == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
const int ctr[2] = {
- BLI_rcti_cent_x(&vod->ar->winrct),
- BLI_rcti_cent_y(&vod->ar->winrct),
+ BLI_rcti_cent_x(winrct),
+ BLI_rcti_cent_y(winrct),
};
- const float len_new = 5 + len_v2v2_int(ctr, xy);
- const float len_old = 5 + len_v2v2_int(ctr, &vod->origx);
- zfac = vod->dist_prev * ((len_old + 5) / (len_new + 5)) / vod->rv3d->dist;
+ float len_new = 5 + len_v2v2_int(ctr, xy);
+ float len_old = 5 + len_v2v2_int(ctr, xy_orig);
+
+ /* intentionally ignore 'zoom_invert' for scale */
+ if (zoom_invert_force) {
+ SWAP(float, len_new, len_old);
+ }
+
+ zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val;
}
else { /* USER_ZOOM_DOLLY */
- float len1, len2;
-
+ float len_new = 5;
+ float len_old = 5;
+
if (U.uiflag & USER_ZOOM_HORIZ) {
- len1 = (vod->ar->winrct.xmax - xy[0]) + 5;
- len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+ len_new += (winrct->xmax - xy[0]);
+ len_old += (winrct->xmax - xy_orig[0]);
}
else {
- len1 = (vod->ar->winrct.ymax - xy[1]) + 5;
- len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
- }
- if (zoom_invert) {
- SWAP(float, len1, len2);
+ len_new += (winrct->ymax - xy[1]);
+ len_old += (winrct->ymax - xy_orig[1]);
}
-
- if (use_cam_zoom) {
- /* zfac is ignored in this case, see below */
-#if 0
- zfac = vod->camzoom_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->camzoom;
-#endif
- }
- else {
- zfac = vod->dist_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->dist;
+
+ if (zoom_invert != zoom_invert_force) {
+ SWAP(float, len_new, len_old);
}
+
+ zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val;
}
- if (!use_cam_zoom) {
- if (zfac != 1.0f) {
- const float zfac_min = dist_range[0] / vod->rv3d->dist;
- const float zfac_max = dist_range[1] / vod->rv3d->dist;
- CLAMP(zfac, zfac_min, zfac_max);
- if (zfac != 1.0f) {
- view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
- }
- }
+ return zfac;
+}
+
+static void viewzoom_apply_camera(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f;
+ float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx,
+ zoomfac, zoomfac_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f && zfac != 0.0f) {
+ /* calculate inverted, then invert again (needed because of camera zoom scaling) */
+ zfac = 1.0f / zfac;
+ view_zoom_mouseloc_camera(
+ vod->scene, vod->v3d,
+ vod->ar, zfac, vod->oldx, vod->oldy);
+ }
+
+ ED_region_tag_redraw(vod->ar);
+}
+
+static void viewzoom_apply_3d(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float dist_range[2];
+
+ ED_view3d_dist_range_get(vod->v3d, dist_range);
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx,
+ vod->rv3d->dist, vod->dist_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f) {
+ const float zfac_min = dist_range[0] / vod->rv3d->dist;
+ const float zfac_max = dist_range[1] / vod->rv3d->dist;
+ CLAMP(zfac, zfac_min, zfac_max);
+
+ view_zoom_mouseloc_3d(
+ vod->ar, zfac, vod->oldx, vod->oldy);
}
/* these limits were in old code too */
@@ -2234,6 +2308,19 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo
ED_region_tag_redraw(vod->ar);
}
+static void viewzoom_apply(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ if ((vod->rv3d->persp == RV3D_CAMOB) &&
+ (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
+ {
+ viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert);
+ }
+ else {
+ viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert);
+ }
+}
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -2294,6 +2381,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int viewzoom_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
ScrArea *sa;
@@ -2326,22 +2414,26 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
+ const float step = 1.2f;
/* this min and max is also in viewmove() */
if (use_cam_zoom) {
- rv3d->camzoom -= 10.0f;
- if (rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom = RV3D_CAMZOOM_MIN;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist < dist_range[1]) {
- view_zoom_mouseloc(ar, 1.2f, mx, my);
+ else {
+ if (rv3d->dist < dist_range[1]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
else {
+ const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
- rv3d->camzoom += 10.0f;
- if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist > dist_range[0]) {
- view_zoom_mouseloc(ar, 0.83333f, mx, my);
+ else {
+ if (rv3d->dist > dist_range[0]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
@@ -2471,7 +2563,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
ot->cancel = viewzoom_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2725,7 +2817,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
ot->cancel = viewdolly_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2748,29 +2840,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
size = max_fff(afm[0], afm[1], afm[2]);
if (ok_dist) {
- /* fix up zoom distance if needed */
+ char persp;
if (rv3d->is_persp) {
- float lens, sensor_size;
- /* offset the view based on the lens */
if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) {
- CameraParams params;
- BKE_camera_params_init(&params);
- params.clipsta = v3d->near;
- params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
-
- lens = params.lens;
- sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+ persp = RV3D_CAMOB;
}
else {
- lens = v3d->lens;
- sensor_size = DEFAULT_SENSOR_WIDTH;
+ persp = RV3D_PERSP;
}
- size = ED_view3d_radius_to_persp_dist(focallength_to_fov(lens, sensor_size), size / 2.0f) * VIEW3D_MARGIN;
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
}
else { /* ortho */
if (size < 0.0001f) {
@@ -2779,7 +2857,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
}
else {
/* adjust zoom so it looks nicer */
- size = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
+ persp = RV3D_ORTHO;
+ }
+ }
+
+ if (ok_dist) {
+ new_dist = ED_view3d_radius_to_dist(v3d, ar, persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->is_persp) {
+ /* don't zoom closer than the near clipping plane */
+ new_dist = max_ff(new_dist, v3d->near * 1.5f);
}
}
}
@@ -2787,15 +2873,6 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
mid_v3_v3v3(new_ofs, min, max);
negate_v3(new_ofs);
- new_dist = size;
-
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- size = (float)ar->winx / (float)ar->winy;
- if (size < 1.0f) size = 1.0f / size;
- new_dist *= size;
- }
-
if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
rv3d->persp = RV3D_PERSP;
ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
@@ -3877,7 +3954,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
char view_opposite;
PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle");
float angle = RNA_property_is_set(op->ptr, prop_angle) ?
- RNA_property_float_get(op->ptr, prop_angle) : DEG2RADF((float)U.pad_rot_angle);
+ RNA_property_float_get(op->ptr, prop_angle) : DEG2RADF(U.pad_rot_angle);
/* no NULL check is needed, poll checks */
v3d = CTX_wm_view3d(C);
@@ -4106,7 +4183,7 @@ static int viewroll_exec(bContext *C, wmOperator *op)
rv3d = ar->regiondata;
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
int type = RNA_enum_get(op->ptr, "type");
- float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF((float)U.pad_rot_angle);
+ float angle = (type == 0) ? RNA_float_get(op->ptr, "angle") : DEG2RADF(U.pad_rot_angle);
float mousevec[3];
float quat_new[4];
@@ -4530,7 +4607,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
bool flip;
bool depth_used = false;
@@ -4565,11 +4642,30 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- float *fp = ED_view3d_cursor3d_get(scene, v3d);
- ED_view3d_cursor3d_position(C, fp, mval);
+ float *fp_curr = ED_view3d_cursor3d_get(scene, v3d);
+ float fp_prev[3];
+
+ copy_v3_v3(fp_prev, fp_curr);
- if (v3d && v3d->localvd)
+ ED_view3d_cursor3d_position(C, fp_curr, mval);
+
+ /* offset the cursor lock to avoid jumping to new offset */
+ if (v3d->ob_centre_cursor) {
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ 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);
+ }
+ }
+
+ if (v3d->localvd)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
else
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
@@ -4579,7 +4675,7 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
{
ED_view3d_cursor3d_update(C, event->mval);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void VIEW3D_OT_cursor3d(wmOperatorType *ot)
@@ -4593,7 +4689,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* api callbacks */
ot->invoke = view3d_cursor3d_invoke;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_region_view3d_active;
/* flags */
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -4719,16 +4815,24 @@ bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d,
bglMats mats; /* ZBuffer depth vars */
float depth_close;
double cent[2], p[3];
+ int margin_arr[] = {0, 2, 4};
+ int i;
+ bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
- depth_close = view_autodist_depth_margin(ar, mval, 4);
+ /* Attempt with low margin's first */
+ i = 0;
+ do {
+ depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
+ depth_ok = (depth_close != FLT_MAX);
+ } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
- if (depth_close != FLT_MAX) {
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ if (depth_ok) {
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
if (gluUnProject(cent[0], cent[1], depth_close,
mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
@@ -4779,8 +4883,8 @@ bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_world
if (depth == FLT_MAX)
return false;
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
bgl_get_mats(&mats);
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index da77c4f75f7..469a7e63903 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -296,10 +296,10 @@ static void fly_update_header(bContext *C, FlyInfo *fly)
"Ctrl: free look, "
"X: Upright x axis (%s), "
"Z: Upright z axis (%s), "
- "(+/- | Wheel): speed"),
+ "(+/- | Wheel): speed"),
WM_bool_as_string(fly->xlock != FLY_AXISLOCK_STATE_OFF),
- WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF));
+ WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF));
ED_area_headerprint(CTX_wm_area(C), header);
#undef HEADER_LENGTH
@@ -806,7 +806,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[1] * time_redraw * -FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
@@ -836,7 +836,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
}
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 11ed9867e2f..f8912345e1c 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -105,8 +105,8 @@ static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d)
if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) {
int bit;
for (bit = 0; bit < 32; bit++) {
- if (scene->obedit->lay & (1 << bit)) {
- v3d->lay |= 1 << bit;
+ if (scene->obedit->lay & (1u << bit)) {
+ v3d->lay |= (1u << bit);
break;
}
}
@@ -161,8 +161,8 @@ static int view3d_layers_exec(bContext *C, wmOperator *op)
v3d->layact = 1 << nr;
else if ((v3d->lay & v3d->layact) == 0) {
for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 25dbc8830fe..95c0ef92680 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -41,14 +41,11 @@ struct BoundBox;
struct DerivedMesh;
struct Object;
struct SmokeDomainSettings;
-struct ViewContext;
struct bAnimVizSettings;
struct bContext;
struct bMotionPath;
struct bPoseChannel;
-struct bScreen;
struct Mesh;
-struct SimDebugData;
struct wmNDOFMotionData;
struct wmOperatorType;
struct wmWindowManager;
@@ -208,7 +205,7 @@ void VIEW3D_OT_localview(struct wmOperatorType *ot);
void VIEW3D_OT_game_start(struct wmOperatorType *ot);
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb);
void ED_view3d_smooth_view_ex(
@@ -225,8 +222,8 @@ void ED_view3d_smooth_view(
const float *ofs, const float *quat, const float *dist, const float *lens,
const int smooth_viewtx);
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect);
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d);
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 8c668b2b8e0..6a2c948aa8d 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -236,6 +236,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "VIEW3D_OT_navigate", FKEY, KM_PRESS, KM_SHIFT, 0);
+ /* value is set to KM_NOTHING to avoid conflicts with click type (see T44251) */
WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 74e3fde0eec..ba0626c58ea 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -605,6 +605,14 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pm
mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
}
+void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obmat[4][4], float pmat[4][4])
+{
+ float vmat[4][4];
+
+ mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, obmat);
+ mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
+}
+
/**
* Uses window coordinates (x,y) and depth component z to find a point in
* modelspace */
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index eba31866f54..98b1e846c70 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -187,8 +187,9 @@ typedef struct RulerInfo {
/* wm state */
wmWindow *win;
- ARegion *ar;
+ ScrArea *sa;
void *draw_handle_pixel;
+ ARegion *ar; /* re-assigned every modal update */
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -435,7 +436,7 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
UnitSettings *unit = &scene->unit;
RulerItem *ruler_item;
RulerInfo *ruler_info = arg;
- RegionView3D *rv3d = ruler_info->ar->regiondata;
+ RegionView3D *rv3d = ar->regiondata;
// ARegion *ar = ruler_info->ar;
const float cap_size = 4.0f;
const float bg_margin = 4.0f * U.pixelsize;
@@ -798,12 +799,14 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
ruler_info->win = win;
- ruler_info->ar = ar;
+ ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
ruler_info, REGION_DRAW_POST_PIXEL);
view3d_ruler_header_update(sa);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
WM_cursor_modal_set(win, BC_CROSSCURSOR);
WM_event_add_modal_handler(C, op);
@@ -825,15 +828,17 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
int exit_code = OPERATOR_RUNNING_MODAL;
RulerInfo *ruler_info = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = ruler_info->ar;
+ ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
/* its possible to change spaces while running the operator [#34894] */
- if (UNLIKELY(ar != CTX_wm_region(C))) {
+ if (UNLIKELY(sa != ruler_info->sa)) {
exit_code = OPERATOR_FINISHED;
goto exit;
}
+ ruler_info->ar = ar;
+
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
@@ -1019,6 +1024,13 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_draw) {
view3d_ruler_header_update(sa);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d0f22ba58c5..49e42cf164a 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -725,7 +725,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv,
}
static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
rcti rect;
@@ -1641,7 +1641,7 @@ static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, con
}
static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me;
MVert *mvert;
struct ImBuf *ibuf;
@@ -1662,7 +1662,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (use_zbuf) {
selar = MEM_callocN(me->totvert + 1, "selar");
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
rt = ibuf->rect;
@@ -2185,7 +2185,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
static bool mouse_weight_paint_vertex_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
- const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me = obact->data; /* already checked for NULL */
unsigned int index = 0;
@@ -2453,7 +2453,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv,
}
static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
bool bbsel;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 0608c35129d..8bb84d00c83 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -31,9 +31,7 @@
#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_meta_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -43,11 +41,9 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
-#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -60,7 +56,6 @@
#include "ED_transverts.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
-#include "ED_curve.h"
#include "view3d_intern.h"
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 4888c6846d2..529e5fcf756 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -688,7 +688,7 @@ static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
return false;
}
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
{
/* return 1: draw */
@@ -697,7 +697,7 @@ bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float ob
if (bb == NULL) return true;
if (bb->flag & BOUNDBOX_DISABLED) return true;
- mul_m4_m4m4(persmatob, rv3d->persmat, obmat);
+ mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
return view3d_boundbox_clip_m4(bb, persmatob);
}
@@ -710,7 +710,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
}
-float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
+float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y)
{
ViewDepths *vd = vc->rv3d->depths;
@@ -729,16 +729,19 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d)
rv3d->depths->damaged = true;
}
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2])
+void ED_view3d_dist_range_get(
+ const View3D *v3d,
+ float r_dist_range[2])
{
r_dist_range[0] = v3d->grid * 0.001f;
r_dist_range[1] = v3d->far * 10.0f;
}
/* copies logic of get_view3d_viewplane(), keep in sync */
-bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend,
- const bool use_ortho_factor)
+bool ED_view3d_clip_range_get(
+ const View3D *v3d, const RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend,
+ const bool use_ortho_factor)
{
CameraParams params;
@@ -758,8 +761,9 @@ bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta,
}
/* also exposed in previewrender.c */
-bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
- rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
+bool ED_view3d_viewplane_get(
+ const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
+ rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
{
CameraParams params;
@@ -797,7 +801,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, View3D *v3d, const rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
@@ -917,7 +921,7 @@ bool ED_view3d_lock(RegionView3D *rv3d)
}
/* don't set windows active in here, is used by renderwin too */
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
{
if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */
if (v3d->camera) {
@@ -956,7 +960,7 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
}
else if (v3d->ob_centre_cursor) {
float vec[3];
- copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, v3d));
+ copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
use_lock_ofs = true;
}
@@ -1214,7 +1218,7 @@ static bool view3d_localview_init(
View3D *v3d = sa->spacedata.first;
Base *base;
float min[3], max[3], box[3], mid[3];
- float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f;
+ float size = 0.0f;
unsigned int locallay;
bool ok = false;
@@ -1252,13 +1256,6 @@ static bool view3d_localview_init(
sub_v3_v3v3(box, max, min);
size = max_fff(box[0], box[1], box[2]);
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
-
- /* perspective size (we always switch out of camera view so no need to use its lens size) */
- size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN;
- size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
}
if (ok == true) {
@@ -1275,6 +1272,7 @@ static bool view3d_localview_init(
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
+ bool ok_dist = true;
/* new view values */
Object *camera_old = NULL;
@@ -1290,25 +1288,24 @@ static bool view3d_localview_init(
camera_old = v3d->camera;
}
- /* perspective should be a bit farther away to look nice */
- if (rv3d->persp != RV3D_ORTHO) {
- dist_new = size_persp;
- }
- else {
- dist_new = size_ortho;
+ if (rv3d->persp == RV3D_ORTHO) {
+ if (size < 0.0001f) {
+ ok_dist = false;
+ }
}
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- float asp = (float)ar->winx / (float)ar->winy;
- if (asp < 1.0f) asp = 1.0f / asp;
- dist_new *= asp;
+ if (ok_dist) {
+ dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->persp == RV3D_PERSP) {
+ /* don't zoom closer than the near clipping plane */
+ dist_new = max_ff(dist_new, v3d->near * 1.5f);
+ }
}
ED_view3d_smooth_view_ex(
wm, win, sa,
v3d, ar, camera_old, NULL,
- ofs_new, NULL, &dist_new, NULL,
+ ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
smooth_viewtx);
}
}
@@ -1715,21 +1712,116 @@ void VIEW3D_OT_game_start(wmOperatorType *ot)
/* ************************************** */
-float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3])
+float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
{
- return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
+ return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
}
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius)
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
{
- return (radius / 2.0f) * fabsf(1.0f / cosf((((float)M_PI) - angle) / 2.0f));
+ return radius * (1.0f / tanf(angle / 2.0f));
}
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius)
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
{
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
+/**
+ * Return a new RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param ar Can be NULL if \a use_aspect is false.
+ * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect Increase the distance to account for non 1:1 view aspect.
+ * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
+float ED_view3d_radius_to_dist(
+ const View3D *v3d, const ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius)
+{
+ float dist;
+
+ BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
+ BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
+
+ if (persp == RV3D_ORTHO) {
+ dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
+ }
+ else {
+ float lens, sensor_size, zoom;
+ float angle;
+
+ if (persp == RV3D_CAMOB) {
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ params.clipsta = v3d->near;
+ params.clipend = v3d->far;
+ BKE_camera_params_from_object(&params, v3d->camera);
+
+ lens = params.lens;
+ sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+
+ /* ignore 'rv3d->camzoom' because we wan't to fit to the cameras frame */
+ zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
+ }
+ else {
+ lens = v3d->lens;
+ sensor_size = DEFAULT_SENSOR_WIDTH;
+ zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+
+ angle = focallength_to_fov(lens, sensor_size);
+
+ /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
+ angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
+
+ dist = ED_view3d_radius_to_dist_persp(angle, radius);
+ }
+
+ if (use_aspect) {
+ const RegionView3D *rv3d = ar->regiondata;
+
+ float winx, winy;
+
+ if (persp == RV3D_CAMOB) {
+ /* camera frame x/y in pixels */
+ winx = ar->winx / rv3d->viewcamtexcofac[0];
+ winy = ar->winy / rv3d->viewcamtexcofac[1];
+ }
+ else {
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ if (winx && winy) {
+ float aspect = winx / winy;
+ if (aspect < 1.0f) {
+ aspect = 1.0f / aspect;
+ }
+ dist *= aspect;
+ }
+ }
+
+ return dist;
+}
+
/* view matrix properties utilities */
/* unused */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 191eeb05c71..1d5c2a3a169 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -26,8 +26,6 @@
/* defines VIEW3D_OT_navigate - walk modal operator */
-//#define NDOF_WALK_DEBUG
-//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -58,6 +56,11 @@
#include "view3d_intern.h" /* own include */
+//#define NDOF_WALK_DEBUG
+//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+
+#define USE_TABLET_SUPPORT
+
/* prototypes */
static float getVelocityZeroTime(const float gravity, const float velocity);
@@ -220,8 +223,7 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
}
-typedef struct WalkTeleport
-{
+typedef struct WalkTeleport {
eWalkTeleportState state;
float duration; /* from user preferences */
float origin[3];
@@ -277,6 +279,14 @@ typedef struct WalkInfo {
/* mouse reverse */
bool is_reversed;
+#ifdef USE_TABLET_SUPPORT
+ /* check if we had a cursor event before */
+ bool is_cursor_first;
+
+ /* tablet devices (we can't relocate the cursor) */
+ bool is_cursor_absolute;
+#endif
+
/* gravity system */
eWalkGravityState gravity_state;
float gravity;
@@ -345,7 +355,7 @@ static void walk_update_header(bContext *C, WalkInfo *walk)
char header[HEADER_LENGTH];
BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB/Return: confirm, Esc/RMB: cancel, "
- "Tab: gravity (%s), "
+ "Tab: gravity (%s), "
"WASD: move around, "
"Shift: fast, Alt: slow, "
"QE: up and down, MMB/Space: teleport, V: jump, "
@@ -520,6 +530,12 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
+#ifdef USE_TABLET_SUPPORT
+ walk->is_cursor_first = true;
+
+ walk->is_cursor_absolute = false;
+#endif
+
walk->active_directions = 0;
#ifdef NDOF_WALK_DRAW_TOOMUCH
@@ -587,10 +603,16 @@ static int walkEnd(bContext *C, WalkInfo *walk)
/* restore the cursor */
WM_cursor_modal_restore(win);
- /* center the mouse */
- WM_cursor_warp(win,
- walk->ar->winrct.xmin + walk->center_mval[0],
- walk->ar->winrct.ymin + walk->center_mval[1]);
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute == false)
+#endif
+ {
+ /* center the mouse */
+ WM_cursor_warp(
+ win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+ }
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
@@ -618,6 +640,27 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_first) {
+ /* wait until we get the 'warp' event */
+ if ((walk->center_mval[0] == event->mval[0]) &&
+ (walk->center_mval[1] == event->mval[1]))
+ {
+ walk->is_cursor_first = false;
+ }
+ return;
+ }
+
+ if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) {
+ walk->is_cursor_absolute = true;
+ copy_v2_v2_int(walk->prev_mval, event->mval);
+ copy_v2_v2_int(walk->center_mval, event->mval);
+ /* without this we can't turn 180d */
+ CLAMP_MIN(walk->mouse_speed, 4.0f);
+ }
+#endif /* USE_TABLET_SUPPORT */
+
+
walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
@@ -628,6 +671,12 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
{
walk->redraw = true;
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute) {
+ /* pass */
+ }
+ else
+#endif
if (wm_event_is_last_mousemove(event)) {
wmWindow *win = CTX_wm_window(C);
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 0c360474b78..0bc38f81dd7 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -55,6 +55,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index e249856b747..1a2e9ab074a 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -50,4 +50,7 @@ defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 061d00424b8..68d77dec619 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -54,6 +54,7 @@
#include "BLI_memarena.h"
#include "BKE_nla.h"
+#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
@@ -98,11 +99,13 @@ static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg)
static void doEdgeSlide(TransInfo *t, float perc);
static void doVertSlide(TransInfo *t, float perc);
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
-static void drawVertSlide(const struct bContext *C, TransInfo *t);
+static void drawEdgeSlide(TransInfo *t);
+static void drawVertSlide(TransInfo *t);
static void len_v3_ensure(float v[3], const float length);
static void postInputRotation(TransInfo *t, float values[3]);
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
+
/* Transform Callbacks */
static void initBend(TransInfo *t);
@@ -164,6 +167,7 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
static void initBoneRoll(TransInfo *t);
static void applyBoneRoll(TransInfo *t, const int mval[2]);
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side);
static void initEdgeSlide(TransInfo *t);
static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
static void applyEdgeSlide(TransInfo *t, const int mval[2]);
@@ -235,6 +239,38 @@ void setTransformViewMatrices(TransInfo *t)
calculateCenter2D(t);
}
+void setTransformViewAspect(TransInfo *t, float r_aspect[3])
+{
+ copy_v3_fl(r_aspect, 1.0f);
+
+ if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->sa->spacedata.first;
+
+ if (t->options & CTX_MASK) {
+ ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
+ }
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
+ else {
+ ED_space_image_get_uv_aspect(sima, &r_aspect[0], &r_aspect[1]);
+ }
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ SpaceClip *sclip = t->sa->spacedata.first;
+
+ if (t->options & CTX_MOVIECLIP) {
+ ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
+ }
+ else {
+ ED_space_clip_get_aspect(sclip, &r_aspect[0], &r_aspect[1]);
+ }
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ /* depemds on context of usage */
+ }
+}
+
static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
{
float divx, divy;
@@ -288,25 +324,19 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
}
}
else if (t->spacetype == SPACE_IMAGE) {
- float aspx, aspy;
-
if (t->options & CTX_MASK) {
convertViewVec2D_mask(t->view, r_vec, dx, dy);
- ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
else if (t->options & CTX_PAINT_CURVE) {
r_vec[0] = dx;
r_vec[1] = dy;
-
- aspx = aspy = 1.0;
}
else {
convertViewVec2D(t->view, r_vec, dx, dy);
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
- r_vec[0] *= aspx;
- r_vec[1] *= aspy;
+ r_vec[0] *= t->aspect[0];
+ r_vec[1] *= t->aspect[1];
}
else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
convertViewVec2D(t->view, r_vec, dx, dy);
@@ -315,8 +345,6 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
}
else if (t->spacetype == SPACE_CLIP) {
- float aspx, aspy;
-
if (t->options & CTX_MASK) {
convertViewVec2D_mask(t->view, r_vec, dx, dy);
}
@@ -324,21 +352,8 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
convertViewVec2D(t->view, r_vec, dx, dy);
}
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
- }
- else if (t->options & CTX_MASK) {
- /* TODO - NOT WORKING, this isnt so bad since its only display aspect */
- ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- else {
- /* should never happen, quiet warnings */
- BLI_assert(0);
- aspx = aspy = 1.0f;
- }
-
- r_vec[0] *= aspx;
- r_vec[1] *= aspy;
+ r_vec[0] *= t->aspect[0];
+ r_vec[1] *= t->aspect[1];
}
else {
printf("%s: called in an invalid context\n", __func__);
@@ -360,15 +375,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
SpaceImage *sima = t->sa->spacedata.first;
if (t->options & CTX_MASK) {
- float aspx, aspy;
float v[2];
- ED_space_image_get_aspect(sima, &aspx, &aspy);
-
- copy_v2_v2(v, vec);
-
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
@@ -382,11 +392,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[1] = vec[1];
}
else {
- float aspx, aspy, v[2];
+ float v[2];
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- v[0] = vec[0] / aspx;
- v[1] = vec[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
}
@@ -431,15 +440,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip) {
- float aspx, aspy;
float v[2];
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
-
- copy_v2_v2(v, vec);
-
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
@@ -454,13 +458,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
}
}
else if (t->options & CTX_MOVIECLIP) {
- float v[2], aspx, aspy;
-
- copy_v2_v2(v, vec);
- ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
+ float v[2];
- v[0] /= aspx;
- v[1] /= aspy;
+ v[0] = vec[0] / t->aspect[0];
+ v[1] = vec[1] / t->aspect[1];
UI_view2d_view_to_region(t->view, v[0], v[1], &adr[0], &adr[1]);
}
@@ -516,7 +517,6 @@ void applyAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) {
SpaceImage *sima = t->sa->spacedata.first;
- float aspx, aspy;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -526,28 +526,13 @@ void applyAspectRatio(TransInfo *t, float vec[2])
vec[1] *= height;
}
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- vec[0] /= aspx;
- vec[1] /= aspy;
+ vec[0] /= t->aspect[0];
+ vec[1] /= t->aspect[1];
}
else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- SpaceClip *sc = t->sa->spacedata.first;
- float aspx, aspy;
-
-
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
-
- vec[0] /= aspx;
- vec[1] /= aspy;
- }
- else if (t->options & CTX_MASK) {
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
-
- vec[0] /= aspx;
- vec[1] /= aspy;
- }
+ vec[0] /= t->aspect[0];
+ vec[1] /= t->aspect[1];
}
}
}
@@ -556,7 +541,6 @@ void removeAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
SpaceImage *sima = t->sa->spacedata.first;
- float aspx, aspy;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -566,24 +550,13 @@ void removeAspectRatio(TransInfo *t, float vec[2])
vec[1] /= height;
}
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- vec[0] *= aspx;
- vec[1] *= aspy;
+ vec[0] *= t->aspect[0];
+ vec[1] *= t->aspect[1];
}
else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- SpaceClip *sc = t->sa->spacedata.first;
- float aspx = 1.0f, aspy = 1.0f;
-
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
- }
- else if (t->options & CTX_MASK) {
- ED_space_clip_get_aspect(sc, &aspx, &aspy);
- }
-
- vec[0] *= aspx;
- vec[1] *= aspy;
+ vec[0] *= t->aspect[0];
+ vec[1] *= t->aspect[1];
}
}
}
@@ -729,7 +702,6 @@ static void view_editmove(unsigned short UNUSED(event))
switch (event) {
case WHEELUPMOUSE:
-
if (G.qual & LR_SHIFTKEY) {
if (G.qual & LR_ALTKEY) {
G.qual &= ~LR_SHIFTKEY;
@@ -795,35 +767,38 @@ static void view_editmove(unsigned short UNUSED(event))
/* ************************************************* */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-#define TFM_MODAL_CANCEL 1
-#define TFM_MODAL_CONFIRM 2
-#define TFM_MODAL_TRANSLATE 3
-#define TFM_MODAL_ROTATE 4
-#define TFM_MODAL_RESIZE 5
-#define TFM_MODAL_SNAP_INV_ON 6
-#define TFM_MODAL_SNAP_INV_OFF 7
-#define TFM_MODAL_SNAP_TOGGLE 8
-#define TFM_MODAL_AXIS_X 9
-#define TFM_MODAL_AXIS_Y 10
-#define TFM_MODAL_AXIS_Z 11
-#define TFM_MODAL_PLANE_X 12
-#define TFM_MODAL_PLANE_Y 13
-#define TFM_MODAL_PLANE_Z 14
-#define TFM_MODAL_CONS_OFF 15
-#define TFM_MODAL_ADD_SNAP 16
-#define TFM_MODAL_REMOVE_SNAP 17
-/* 18 and 19 used by numinput, defined in transform.h
- * */
-#define TFM_MODAL_PROPSIZE_UP 20
-#define TFM_MODAL_PROPSIZE_DOWN 21
-#define TFM_MODAL_AUTOIK_LEN_INC 22
-#define TFM_MODAL_AUTOIK_LEN_DEC 23
-
-#define TFM_MODAL_EDGESLIDE_UP 24
-#define TFM_MODAL_EDGESLIDE_DOWN 25
+enum {
+ TFM_MODAL_CANCEL = 1,
+ TFM_MODAL_CONFIRM = 2,
+ TFM_MODAL_TRANSLATE = 3,
+ TFM_MODAL_ROTATE = 4,
+ TFM_MODAL_RESIZE = 5,
+ TFM_MODAL_SNAP_INV_ON = 6,
+ TFM_MODAL_SNAP_INV_OFF = 7,
+ TFM_MODAL_SNAP_TOGGLE = 8,
+ TFM_MODAL_AXIS_X = 9,
+ TFM_MODAL_AXIS_Y = 10,
+ TFM_MODAL_AXIS_Z = 11,
+ TFM_MODAL_PLANE_X = 12,
+ TFM_MODAL_PLANE_Y = 13,
+ TFM_MODAL_PLANE_Z = 14,
+ TFM_MODAL_CONS_OFF = 15,
+ TFM_MODAL_ADD_SNAP = 16,
+ TFM_MODAL_REMOVE_SNAP = 17,
+
+/* 18 and 19 used by numinput, defined in transform.h */
+
+ TFM_MODAL_PROPSIZE_UP = 20,
+ TFM_MODAL_PROPSIZE_DOWN = 21,
+ TFM_MODAL_AUTOIK_LEN_INC = 22,
+ TFM_MODAL_AUTOIK_LEN_DEC = 23,
+
+ TFM_MODAL_EDGESLIDE_UP = 24,
+ TFM_MODAL_EDGESLIDE_DOWN = 25,
/* for analog input, like trackpad */
-#define TFM_MODAL_PROPSIZE 26
+ TFM_MODAL_PROPSIZE = 26,
+};
/* called in transform_ops.c, on each regeneration of keymaps */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
@@ -868,8 +843,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
@@ -888,8 +863,12 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
@@ -907,7 +886,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
{
if (!(t->flag & T_NO_CONSTRAINT)) {
int constraint_axis, constraint_plane;
- int edit_2d = (t->flag & T_2D_EDIT);
+ const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
char axis;
@@ -1230,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1240,17 +1219,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case TFM_MODAL_EDGESLIDE_UP:
- case TFM_MODAL_EDGESLIDE_DOWN:
- t->redraw |= TREDRAW_HARD;
- handled = true;
- break;
case TFM_MODAL_AUTOIK_LEN_INC:
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, 1);
@@ -1265,6 +1239,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
+ /* Those two are only handled in transform's own handler, see T44634! */
+ case TFM_MODAL_EDGESLIDE_UP:
+ case TFM_MODAL_EDGESLIDE_DOWN:
default:
break;
}
@@ -1413,7 +1390,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADPLUSKEY:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1434,7 +1411,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADMINUS:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw = TREDRAW_HARD;
handled = true;
@@ -1571,7 +1548,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
if (cent3d) {
// Copy center from constraint center. Transform center can be local
- copy_v3_v3(cent3d, t->con.center);
+ copy_v3_v3(cent3d, t->center_global);
}
}
@@ -1824,8 +1801,8 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
drawSnapping(C, t);
/* edge slide, vert slide */
- drawEdgeSlide(C, t);
- drawVertSlide(C, t);
+ drawEdgeSlide(t);
+ drawVertSlide(t);
}
/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
@@ -1934,7 +1911,11 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
!RNA_property_is_set(op->ptr, prop))
{
- if (t->obedit)
+ if (t->spacetype == SPACE_IPO)
+ ts->proportional_fcurve = proportional;
+ else if (t->spacetype == SPACE_ACTION)
+ ts->proportional_action = proportional;
+ else if (t->obedit)
ts->proportional = proportional;
else if (t->options & CTX_MASK)
ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -1985,7 +1966,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
- RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR);
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0);
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
@@ -2013,6 +1994,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
}
+
+ {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
+
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
+ }
+ }
}
/* note: caller needs to free 't' on a 0 return */
@@ -2085,6 +2078,18 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
+ else if (t->spacetype == SPACE_IPO) {
+ unit_m3(t->spacemtx);
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ unit_m3(t->spacemtx);
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
else
unit_m3(t->spacemtx);
@@ -2184,18 +2189,28 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
case TFM_BONESIZE:
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
bArmature *arm = t->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE)
+ if (arm->drawtype == ARM_ENVELOPE) {
initBoneEnvelope(t);
- else
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ }
+ else {
initBoneSize(t);
+ }
break;
}
case TFM_BONE_ENVELOPE:
initBoneEnvelope(t);
break;
+ case TFM_BONE_ENVELOPE_DIST:
+ initBoneEnvelope(t);
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ break;
case TFM_EDGE_SLIDE:
- initEdgeSlide(t);
+ {
+ const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
+ initEdgeSlide_ex(t, use_double_side);
break;
+ }
case TFM_VERT_SLIDE:
initVertSlide(t);
break;
@@ -2254,7 +2269,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
return 0;
}
-
/* overwrite initial values if operator supplied a non-null vector */
if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
@@ -2512,8 +2526,8 @@ static void protectedQuaternionBits(short protectflag, float quat[4], const floa
static void constraintTransLim(TransInfo *t, TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
- bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
+ const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
+ const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
@@ -2528,7 +2542,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
/* Evaluate valid constraints */
for (con = td->con; con; con = con->next) {
- bConstraintTypeInfo *cti = NULL;
+ const bConstraintTypeInfo *cti = NULL;
ListBase targets = {NULL, NULL};
/* only consider constraint if enabled */
@@ -2615,7 +2629,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
bConstraintOb cob;
bConstraint *con;
bool do_limit = false;
@@ -2682,7 +2696,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
static void constraintSizeLim(TransInfo *t, TransData *td)
{
if (td->con && td->ext) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
float size_sign[3], size_abs[3];
@@ -2806,10 +2820,11 @@ static void initBend(TransInfo *t)
t->num.unit_type[0] = B_UNIT_ROTATION;
t->num.unit_type[1] = B_UNIT_LENGTH;
- t->flag |= T_NO_CONSTRAINT;
+ t->flag |= T_NO_CONSTRAINT | T_FREE_CUSTOMDATA;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
+ calculateCenterGlobal(t);
t->val = 0.0f;
@@ -2884,6 +2899,8 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
values.scale = values.scale / data->warp_init_dist;
}
+ copy_v2_v2(t->values, values.vector);
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
@@ -2901,8 +2918,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
WM_bool_as_string(is_clamp));
}
- copy_v2_v2(t->values, values.vector);
-
values.angle *= -1.0f;
values.scale *= data->warp_init_dist;
@@ -2957,6 +2972,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(vec, pivot);
mul_m3_v3(td->smtx, vec);
+
+ /* rotation */
+ if ((t->flag & T_POINTS) == 0) {
+ ElementRotation(t, td, mat, V3D_LOCAL);
+ }
+
+ /* location */
copy_v3_v3(td->loc, vec);
}
@@ -3052,6 +3074,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &value);
+ t->values[0] = value;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -3065,8 +3089,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
}
- t->values[0] = value;
-
unit_m3(smat);
// Custom data signals shear direction
@@ -3329,7 +3351,7 @@ static void applyResize(TransInfo *t, const int mval[2])
ratio = t->values[0];
}
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, ratio);
snapGridIncrement(t, size);
@@ -3435,12 +3457,10 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
{
TransData *td;
float size[3], mat[3][3];
- float ratio;
int i;
char str[MAX_INFO_LEN];
- ratio = t->values[0];
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, t->values[0]);
snapGridIncrement(t, size);
@@ -3545,10 +3565,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
- if (ratio < 0)
- ratio = 0.0f;
- else if (ratio > 1)
- ratio = 1.0f;
+ CLAMP(ratio, 0.0f, 1.0f);
t->values[0] = ratio;
@@ -3917,6 +3934,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
final = angle_wrap_rad(final);
}
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -3933,8 +3952,6 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
- t->values[0] = final;
-
applyRotationValue(t, final, t->axis);
recalcData(t);
@@ -4006,7 +4023,9 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
char str[MAX_INFO_LEN];
size_t ofs = 0;
float axis1[3], axis2[3];
+#if 0 /* UNUSED */
float mat[3][3], totmat[3][3], smat[3][3];
+#endif
float phi[2];
copy_v3_v3(axis1, t->persinv[0]);
@@ -4014,13 +4033,14 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
normalize_v3(axis1);
normalize_v3(axis2);
- phi[0] = t->values[0];
- phi[1] = t->values[1];
+ copy_v2_v2(phi, t->values);
snapGridIncrement(t, phi);
applyNumInput(&t->num, phi);
+ copy_v2_v2(t->values, phi);
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
@@ -4038,6 +4058,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
}
+#if 0 /* UNUSED */
axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
@@ -4045,6 +4066,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
// TRANSFORM_FIX_ME
//copy_m3_m3(t->mat, mat); // used in manipulator
+#endif
applyTrackballValue(t, axis1, axis2, phi);
@@ -4370,6 +4392,8 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &distance);
+ t->values[0] = -distance;
+
/* header print for NumInput */
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
@@ -4397,9 +4421,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
/* done with header string */
-
- t->values[0] = -distance;
-
for (i = 0; i < t->total; i++, td++) {
float tdistance; /* temp dist */
if (td->flag & TD_NOACTION)
@@ -4466,6 +4487,8 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4543,6 +4566,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4621,6 +4646,8 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4719,6 +4746,8 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4791,6 +4820,8 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &distance);
+ t->values[0] = distance;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4804,8 +4835,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
}
- t->values[0] = distance;
-
if (t->con.applyRot && t->con.mode & CON_APPLY) {
t->con.applyRot(t, NULL, axis, NULL);
}
@@ -4878,12 +4907,14 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
weight = t->values[0];
- if (weight > 1.0f) weight = 1.0f;
+ CLAMP_MAX(weight, 1.0f);
snapGridIncrement(t, &weight);
applyNumInput(&t->num, &weight);
+ t->values[0] = weight;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -4956,12 +4987,14 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
crease = t->values[0];
- if (crease > 1.0f) crease = 1.0f;
+ CLAMP_MAX(crease, 1.0f);
snapGridIncrement(t, &crease);
applyNumInput(&t->num, &crease);
+ t->values[0] = crease;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -5095,7 +5128,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
ratio = t->values[0];
}
- size[0] = size[1] = size[2] = ratio;
+ copy_v3_fl(size, ratio);
snapGridIncrement(t, size);
@@ -5103,6 +5136,8 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
constraintNumInput(t, size);
}
+ copy_v3_v3(t->values, size);
+
size_to_mat3(mat, size);
if (t->con.applySize) {
@@ -5169,6 +5204,8 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &ratio);
+ t->values[0] = ratio;
+
/* header print for NumInput */
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -5256,11 +5293,22 @@ static void slide_origdata_create_data_vert(
loop_weights = BLI_array_alloca(loop_weights, l_num);
for (j = 0; j < l_num; j++) {
BMLoop *l = BM_iter_step(&liter);
- if (!BLI_ghash_haskey(sod->origfaces, l->f)) {
+ BMLoop *l_prev, *l_next;
+ void **val_p;
+ if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) {
BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true);
- BLI_ghash_insert(sod->origfaces, l->f, f_copy);
+ *val_p = f_copy;
}
- loop_weights[j] = BM_loop_calc_face_angle(l);
+
+ if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
+ (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON)))
+ {
+ loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
+
}
/* store cd_loop_groups */
@@ -5328,6 +5376,13 @@ static void slide_origdata_interp_data_vert(
int j, l_num;
float *loop_weights;
const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
+ const float *v_proj_axis = sv->v->no;
+ /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
+ float v_proj[3][3];
+
+ if (do_loop_weight) {
+ project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
+ }
// BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
@@ -5348,11 +5403,44 @@ static void slide_origdata_interp_data_vert(
/* weight the loop */
if (do_loop_weight) {
- const float *v_prev = slide_origdata_orig_vert_co(sod, l->prev->v);
- const float *v_next = slide_origdata_orig_vert_co(sod, l->next->v);
- const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, v_prev, sv->co_orig_3d, v_next, f_copy->no);
- const float eps = 0.00001f;
- loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ const float eps = 1.0e-8f;
+ const BMLoop *l_prev = l->prev;
+ const BMLoop *l_next = l->next;
+ const float *co_prev = slide_origdata_orig_vert_co(sod, l_prev->v);
+ const float *co_next = slide_origdata_orig_vert_co(sod, l_next->v);
+ bool co_prev_ok;
+ bool co_next_ok;
+
+
+ /* 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);
+ 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_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);
+ }
+
+ if (co_prev_ok && co_next_ok) {
+ const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, UNPACK3(v_proj), v_proj_axis);
+
+ loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
+ if (UNLIKELY(!isfinite(loop_weights[j]))) {
+ loop_weights[j] = 0.0f;
+ }
+ }
+ else {
+ loop_weights[j] = 0.0f;
+ }
}
}
@@ -5423,6 +5511,19 @@ static void slide_origdata_free_date(
/** \name Transform Edge Slide
* \{ */
+static void calcEdgeSlideCustomPoints(struct TransInfo *t)
+{
+ EdgeSlideData *sld = t->customData;
+
+ setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+}
+
+
static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
{
BMIter iter;
@@ -5438,7 +5539,7 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
}
/* interpoaltes along a line made up of 2 segments (used for edge slide) */
-static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t)
+static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
{
float t_mid, t_delta;
@@ -5446,17 +5547,28 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[
t_mid = line_point_factor_v3(v2, v1, v3);
t_delta = t - t_mid;
- if (fabsf(t_delta) < FLT_EPSILON) {
- copy_v3_v3(p, v2);
- }
- else if (t_delta < 0.0f) {
- interp_v3_v3v3(p, v1, v2, t / t_mid);
+ if (t_delta < 0.0f) {
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v2);
+ }
+ else {
+ interp_v3_v3v3(p, v1, v2, t / t_mid);
+ }
}
else {
- interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid));
+ t = t - t_mid;
+ t_mid = 1.0f - t_mid;
+
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v3);
+ }
+ else {
+ interp_v3_v3v3(p, v2, v3, t / t_mid);
+ }
}
}
+
static void len_v3_ensure(float v[3], const float length)
{
normalize_v3(v);
@@ -5601,7 +5713,171 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
return NULL;
}
-static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
+/**
+ * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
+ */
+static void calcEdgeSlide_mval_range(
+ TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
+ const float mval[2], const bool use_btree_disp, const bool use_calc_direction)
+{
+ TransDataEdgeSlideVert *sv_array = sld->sv;
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ ARegion *ar = t->ar;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+ float projectMat[4][4];
+ BMBVHTree *btree;
+
+ /* only for use_calc_direction */
+ float (*loop_dir)[3] = NULL, *loop_maxdist = NULL;
+
+ float mval_start[2], mval_end[2];
+ float mval_dir[3], dist_best_sq;
+ BMIter iter;
+ BMEdge *e;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ }
+
+ if (!rv3d) {
+ /* ok, let's try to survive this */
+ unit_m4(projectMat);
+ }
+ else {
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ }
+
+ if (use_btree_disp) {
+ btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+ }
+ else {
+ btree = NULL;
+ }
+
+ /* find mouse vectors, the global one, and one per loop in case we have
+ * multiple loops selected, in case they are oriented different */
+ zero_v3(mval_dir);
+ dist_best_sq = -1.0f;
+
+ if (use_calc_direction) {
+ loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
+ loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
+ copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ int i;
+
+ /* search cross edges for visible edge to the mouse cursor,
+ * then use the shared vertex to calculate screen vector*/
+ for (i = 0; i < 2; i++) {
+ BMIter iter_other;
+ BMEdge *e_other;
+
+ BMVert *v = i ? e->v1 : e->v2;
+ BM_ITER_ELEM (e_other, &iter_other, v, BM_EDGES_OF_VERT) {
+ /* screen-space coords */
+ float sco_a[3], sco_b[3];
+ float dist_sq;
+ int j, l_nr;
+
+ if (BM_elem_flag_test(e_other, BM_ELEM_SELECT))
+ continue;
+
+ /* This test is only relevant if object is not wire-drawn! See [#32068]. */
+ if (use_btree_disp && !BMBVH_EdgeVisible(btree, e_other, ar, v3d, t->obedit)) {
+ continue;
+ }
+
+ BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
+ j = sv_table[BM_elem_index_get(v)];
+
+ if (sv_array[j].v_side[1]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[1]->co, sco_b, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_b, v->co, sv_array[j].dir_side[1]);
+ ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
+ }
+
+ if (sv_array[j].v_side[0]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[0]->co, sco_a, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_a, v->co, sv_array[j].dir_side[0]);
+ ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
+ }
+
+ /* global direction */
+ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
+ if ((dist_best_sq == -1.0f) ||
+ /* intentionally use 2d size on 3d vector */
+ (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
+ {
+ dist_best_sq = dist_sq;
+ sub_v3_v3v3(mval_dir, sco_b, sco_a);
+ }
+
+ if (use_calc_direction) {
+ /* per loop direction */
+ l_nr = sv_array[j].loop_nr;
+ if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
+ loop_maxdist[l_nr] = dist_sq;
+ sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (use_calc_direction) {
+ int i;
+ sv_array = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv_array++) {
+ /* switch a/b if loop direction is different from global direction */
+ int l_nr = sv_array->loop_nr;
+ if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
+ swap_v3_v3(sv_array->dir_side[0], sv_array->dir_side[1]);
+ SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]);
+ }
+ }
+
+ MEM_freeN(loop_dir);
+ MEM_freeN(loop_maxdist);
+ }
+
+ /* possible all of the edge loops are pointing directly at the view */
+ if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
+ mval_dir[0] = 0.0f;
+ mval_dir[1] = 100.0f;
+ }
+
+ /* zero out start */
+ zero_v2(mval_start);
+
+ /* dir holds a vector along edge loop */
+ copy_v2_v2(mval_end, mval_dir);
+ mul_v2_fl(mval_end, 0.5f);
+
+ sld->mval_start[0] = t->mval[0] + mval_start[0];
+ sld->mval_start[1] = t->mval[1] + mval_start[1];
+
+ sld->mval_end[0] = t->mval[0] + mval_end[0];
+ sld->mval_end[1] = t->mval[1] + mval_end[1];
+
+ if (btree) {
+ BKE_bmbvh_free(btree);
+ }
+}
+
+static void calcEdgeSlide_non_proportional(
+ TransInfo *t, EdgeSlideData *sld, const float mval[2])
{
TransDataEdgeSlideVert *sv = sld->sv;
@@ -5631,7 +5907,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
for (i = 0; i < sld->totsv; i++, sv++) {
/* Set length */
- sv->edge_len = len_v3v3(sv->dir_a, sv->dir_b);
+ sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
dist_sq = len_squared_v2v2(mval, v_proj);
@@ -5646,7 +5922,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
}
}
-static bool createEdgeSlideVerts(TransInfo *t)
+static bool createEdgeSlideVerts_double_side(TransInfo *t)
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
@@ -5655,24 +5931,13 @@ static bool createEdgeSlideVerts(TransInfo *t)
BMVert *v;
TransDataEdgeSlideVert *sv_array;
int sv_tot;
- BMBVHTree *btree;
int *sv_table; /* BMVert -> sv_array index */
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int numsel, i, j, loop_nr;
+ bool use_btree_disp = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
- float projectMat[4][4];
- float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- float mval_start[2], mval_end[2];
- float mval_dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
- int numsel, i, j, loop_nr, l_nr;
- int use_btree_disp;
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- }
slide_origdata_init_flag(t, &sld->orig_data);
@@ -5680,14 +5945,6 @@ static bool createEdgeSlideVerts(TransInfo *t)
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
- }
-
/*ensure valid selection*/
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
@@ -5859,14 +6116,14 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a || l_a_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_a, vec_a);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[0], vec_a);
}
if (l_b || l_b_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_b, vec_b);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[1], vec_b);
}
v_prev = v;
@@ -5885,23 +6142,23 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a);
+ get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
}
else {
- sub_v3_v3v3(sv->dir_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
}
}
if (l_b) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b);
+ get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
}
else {
- sub_v3_v3v3(sv->dir_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co);
}
}
@@ -5972,142 +6229,228 @@ static bool createEdgeSlideVerts(TransInfo *t)
#undef EDGESLIDE_VERT_IS_INNER
}
- /* use for visibility checks */
- use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
- if (use_btree_disp) {
- btree = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
- }
- else {
- btree = NULL;
+ sld->sv = sv_array;
+ sld->totsv = sv_tot;
+
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, true);
- /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+ /* create copies of faces for customdata projection */
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
- sld->sv = sv_array;
- sld->totsv = sv_tot;
+ if (rv3d) {
+ calcEdgeSlide_non_proportional(t, sld, mval);
+ }
+
+ sld->em = em;
- /* find mouse vectors, the global one, and one per loop in case we have
- * multiple loops selected, in case they are oriented different */
- zero_v3(mval_dir);
- maxdist = -1.0f;
+ sld->perc = 0.0f;
+
+ t->customData = sld;
+
+ MEM_freeN(sv_table);
- loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir");
- loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
- fill_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ return true;
+}
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- BMIter iter2;
- BMEdge *e2;
- float d;
+/**
+ * A simple version of #createEdgeSlideVerts
+ * Which assumes the longest unselected.
+ */
+static bool createEdgeSlideVerts_single_side(TransInfo *t)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v;
+ TransDataEdgeSlideVert *sv_array;
+ int sv_tot;
+ int *sv_table; /* BMVert -> sv_array index */
+ EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int i, j, loop_nr;
+ bool use_btree_disp = false;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
- /* search cross edges for visible edge to the mouse cursor,
- * then use the shared vertex to calculate screen vector*/
- for (i = 0; i < 2; i++) {
- v = i ? e->v1 : e->v2;
- BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
- /* screen-space coords */
- float sco_a[3], sco_b[3];
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ }
- if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
- continue;
+ slide_origdata_init_flag(t, &sld->orig_data);
- /* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
- continue;
+ sld->is_proportional = true;
+ sld->curr_sv_index = 0;
+ /* heppans to be best for single-sided */
+ sld->flipped_vtx = true;
+
+ /* ensure valid selection */
+ j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float len_sq_max = -1.0f;
+ BMIter iter2;
+ BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > len_sq_max) {
+ len_sq_max = len_sq;
+ v->e = e;
}
+ }
+ }
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- j = sv_table[BM_elem_index_get(v)];
+ if (len_sq_max != -1.0f) {
+ j++;
+ }
+ }
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
- if (sv_array[j].v_b) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_b->co, sco_b, projectMat);
- }
- else {
- add_v3_v3v3(sco_b, v->co, sv_array[j].dir_b);
- ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
- }
-
- if (sv_array[j].v_a) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_a->co, sco_a, projectMat);
+ if (!j) {
+ return false;
+ }
+
+
+ sv_tot = j;
+ BLI_assert(sv_tot != 0);
+ /* over alloc */
+ sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
+
+ /* same loop for all loops, weak but we dont connect loops in this case */
+ loop_nr = 1;
+
+ sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
+
+ j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ sv_table[i] = -1;
+ if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
+ if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
+ TransDataEdgeSlideVert *sv;
+ sv = &sv_array[j];
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->v_side[0] = BM_edge_other_vert(v->e, v);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
+ sv->loop_nr = 0;
+ sv_table[i] = j;
+ j += 1;
+ }
+ }
+ }
+
+ /* check for wire vertices,
+ * interpolate the directions of wire verts between non-wire verts */
+ if (sv_tot != bm->totvert) {
+ const int sv_tot_nowire = sv_tot;
+ TransDataEdgeSlideVert *sv_iter = sv_array;
+ int i;
+ for (i = 0; i < sv_tot_nowire; i++, sv_iter++) {
+ BMIter eiter;
+ BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
+ /* walk over wire */
+ TransDataEdgeSlideVert *sv_end = NULL;
+ BMEdge *e_step = e;
+ BMVert *v = sv_iter->v;
+
+ j = sv_tot;
+
+ while (1) {
+ BMVert *v_other = BM_edge_other_vert(e_step, v);
+ int endpoint = (
+ (sv_table[BM_elem_index_get(v_other)] != -1) +
+ (BM_vert_is_edge_pair(v_other) == false));
+
+ if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
+ (endpoint == 0))
+ {
+ /* scan down the list */
+ TransDataEdgeSlideVert *sv;
+ BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
+ sv_table[BM_elem_index_get(v_other)] = j;
+ sv = &sv_array[j];
+ sv->v = v_other;
+ copy_v3_v3(sv->v_co_orig, v_other->co);
+ copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
+ j++;
+
+ /* advance! */
+ v = v_other;
+ e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
}
else {
- add_v3_v3v3(sco_a, v->co, sv_array[j].dir_a);
- ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
- }
-
- /* global direction */
- d = dist_to_line_segment_v2(mval, sco_b, sco_a);
- if ((maxdist == -1.0f) ||
- /* intentionally use 2d size on 3d vector */
- (d < maxdist && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
- {
- maxdist = d;
- sub_v3_v3v3(mval_dir, sco_b, sco_a);
+ if ((endpoint == 2) && (sv_tot != j)) {
+ BLI_assert(BM_elem_index_get(v_other) != -1);
+ sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
+ }
+ break;
}
+ }
- /* per loop direction */
- l_nr = sv_array[j].loop_nr;
- if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) {
- loop_maxdist[l_nr] = d;
- sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
+ if (sv_end) {
+ int sv_tot_prev = sv_tot;
+ const float *co_src = sv_iter->v->co;
+ const float *co_dst = sv_end->v->co;
+ const float *dir_src = sv_iter->dir_side[0];
+ const float *dir_dst = sv_end->dir_side[0];
+ sv_tot = j;
+
+ while (j-- != sv_tot_prev) {
+ float factor;
+ factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
+ interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
}
}
}
}
}
- /* possible all of the edge loops are pointing directly at the view */
- if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
- mval_dir[0] = 0.0f;
- mval_dir[1] = 100.0f;
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+
+ sld->sv = sv_array;
+ sld->totsv = sv_tot;
+
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->sa ? t->sa->spacedata.first : NULL;
+ rv3d = t->ar ? t->ar->regiondata : NULL;
+ use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
}
+ calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_btree_disp, false);
+
+ /* create copies of faces for customdata projection */
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
slide_origdata_init_data(t, &sld->orig_data);
slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
- /*create copies of faces for customdata projection*/
- sv_array = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv_array++) {
- /* switch a/b if loop direction is different from global direction */
- l_nr = sv_array->loop_nr;
- if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
- swap_v3_v3(sv_array->dir_a, sv_array->dir_b);
- SWAP(BMVert *, sv_array->v_a, sv_array->v_b);
- }
+ if (rv3d) {
+ calcEdgeSlide_non_proportional(t, sld, mval);
}
- if (rv3d)
- calcNonProportionalEdgeSlide(t, sld, mval);
-
sld->em = em;
- /*zero out start*/
- zero_v2(mval_start);
-
- /*dir holds a vector along edge loop*/
- copy_v2_v2(mval_end, mval_dir);
- mul_v2_fl(mval_end, 0.5f);
-
- sld->mval_start[0] = t->mval[0] + mval_start[0];
- sld->mval_start[1] = t->mval[1] + mval_start[1];
-
- sld->mval_end[0] = t->mval[0] + mval_end[0];
- sld->mval_end[1] = t->mval[1] + mval_end[1];
-
sld->perc = 0.0f;
-
+
t->customData = sld;
-
+
MEM_freeN(sv_table);
- if (btree) {
- BKE_bmbvh_free(btree);
- }
- MEM_freeN(loop_dir);
- MEM_freeN(loop_maxdist);
return true;
}
@@ -6148,15 +6491,23 @@ void freeEdgeSlideVerts(TransInfo *t)
recalcData(t);
}
-static void initEdgeSlide(TransInfo *t)
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
{
EdgeSlideData *sld;
+ bool ok;
t->mode = TFM_EDGE_SLIDE;
t->transform = applyEdgeSlide;
t->handleEvent = handleEventEdgeSlide;
- if (!createEdgeSlideVerts(t)) {
+ if (use_double_side) {
+ ok = createEdgeSlideVerts_double_side(t);
+ }
+ else {
+ ok = createEdgeSlideVerts_single_side(t);
+ }
+
+ if (!ok) {
t->state = TRANS_CANCEL;
return;
}
@@ -6169,7 +6520,7 @@ static void initEdgeSlide(TransInfo *t)
t->customFree = freeEdgeSlideVerts;
/* set custom point first if you want value to be initialized by init */
- setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+ calcEdgeSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
t->idx_max = 0;
@@ -6185,6 +6536,11 @@ static void initEdgeSlide(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+static void initEdgeSlide(TransInfo *t)
+{
+ initEdgeSlide_ex(t, true);
+}
+
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
@@ -6195,35 +6551,40 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
case EKEY:
if (event->val == KM_PRESS) {
sld->is_proportional = !sld->is_proportional;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
if (sld->is_proportional == false) {
sld->flipped_vtx = !sld->flipped_vtx;
}
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case CKEY:
+ /* use like a modifier key */
+ if (event->val == KM_PRESS) {
+ t->flag ^= T_ALT_TRANSFORM;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
}
break;
- }
+ case MOUSEMOVE:
+ calcEdgeSlideCustomPoints(t);
+ break;
default:
break;
}
@@ -6232,23 +6593,16 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
+static void drawEdgeSlide(TransInfo *t)
{
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = (EdgeSlideData *)t->customData;
+ if ((t->mode == TFM_EDGE_SLIDE) && t->customData) {
+ EdgeSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld && sld->is_proportional == false) {
- View3D *v3d = CTX_wm_view3d(C);
- float co_a[3], co_b[3], co_mark[3];
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (sld->perc + 1.0f) / 2.0f;
- const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
- const float guide_size = ctrl_size - 0.5f;
+ if ((sld->is_proportional == false) || (is_clamp == false)) {
+ View3D *v3d = t->view;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
- const int alpha_shade = -30;
-
- add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a);
- add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b);
if (v3d && v3d->zbuf)
glDisable(GL_DEPTH_TEST);
@@ -6261,42 +6615,88 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
glMultMatrixf(t->obedit->obmat);
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
- if (curr_sv->v_a) {
- glVertex3fv(curr_sv->v_a->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- if (curr_sv->v_b) {
- glVertex3fv(curr_sv->v_b->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- bglEnd();
+ if (sld->is_proportional == false) {
+ float co_a[3], co_b[3], co_mark[3];
+ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+ const float fac = (sld->perc + 1.0f) / 2.0f;
+ const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+ const float guide_size = ctrl_size - 0.5f;
+ const int alpha_shade = -30;
+
+ add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
+ add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+ if (curr_sv->v_side[0]) {
+ glVertex3fv(curr_sv->v_side[0]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ if (curr_sv->v_side[1]) {
+ glVertex3fv(curr_sv->v_side[1]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ glEnd();
+ UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+ glPointSize(ctrl_size);
+ bglBegin(GL_POINTS);
+ if (sld->flipped_vtx) {
+ if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co);
+ }
+ else {
+ if (curr_sv->v_side[0]) bglVertex3fv(curr_sv->v_side[0]->co);
+ }
+ bglEnd();
- UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
- glPointSize(ctrl_size);
- bglBegin(GL_POINTS);
- if (sld->flipped_vtx) {
- if (curr_sv->v_b) bglVertex3fv(curr_sv->v_b->co);
+ UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+ glPointSize(guide_size);
+ bglBegin(GL_POINTS);
+#if 0
+ interp_v3_v3v3(co_mark, co_b, co_a, fac);
+ bglVertex3fv(co_mark);
+#endif
+ interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
+ bglVertex3fv(co_mark);
+ bglEnd();
}
else {
- if (curr_sv->v_a) bglVertex3fv(curr_sv->v_a->co);
- }
- bglEnd();
+ if (is_clamp == false) {
+ const int side_index = sld->curr_side_unclamp;
+ TransDataEdgeSlideVert *sv;
+ int i;
+ const int alpha_shade = -160;
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float a[3], b[3];
+
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(a, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(a, sv->dir_side[!side_index]);
+ }
- UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
- glPointSize(guide_size);
- bglBegin(GL_POINTS);
-#if 0
- interp_v3_v3v3(co_mark, co_b, co_a, fac);
- bglVertex3fv(co_mark);
-#endif
- interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- bglVertex3fv(co_mark);
- bglEnd();
+ mul_v3_fl(a, 100.0f);
+ negate_v3_v3(b, a);
+ add_v3_v3(a, sv->v_co_orig);
+ add_v3_v3(b, sv->v_co_orig);
+ glVertex3fv(a);
+ glVertex3fv(b);
+ }
+ glEnd();
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
glPopMatrix();
glPopAttrib();
@@ -6319,17 +6719,30 @@ static void doEdgeSlide(TransInfo *t, float perc)
sv = svlist;
if (sld->is_proportional == true) {
- for (i = 0; i < sld->totsv; i++, sv++) {
- float vec[3];
- if (perc > 0.0f) {
- copy_v3_v3(vec, sv->dir_a);
- mul_v3_fl(vec, perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ if (is_clamp) {
+ const int side_index = (perc < 0.0f);
+ const float perc_final = fabsf(perc);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
}
- else {
- copy_v3_v3(vec, sv->dir_b);
- mul_v3_fl(vec, -perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+
+ sld->curr_side_unclamp = side_index;
+ }
+ else {
+ const int side_index = sld->curr_side_unclamp;
+ const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float dir_flip[3];
+ float perc_final = perc_init;
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+ perc_final *= -1;
+ }
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
}
}
@@ -6339,7 +6752,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
* a/b verts, this could be changed/improved so the distance is still met but the verts are moved along
* their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
*
- * \note len_v3v3(curr_sv->dir_a, curr_sv->dir_b)
+ * \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
@@ -6352,8 +6765,8 @@ static void doEdgeSlide(TransInfo *t, float perc)
if (sv->edge_len > FLT_EPSILON) {
const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
- add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_a);
- add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b);
+ add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+ add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
if (sld->flipped_vtx) {
interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
@@ -6371,46 +6784,43 @@ static void doEdgeSlide(TransInfo *t, float perc)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
char str[MAX_INFO_LEN];
+ size_t ofs = 0;
float final;
EdgeSlideData *sld = t->customData;
bool flipped = sld->flipped_vtx;
bool is_proportional = sld->is_proportional;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
final = t->values[0];
snapGridIncrement(t, &final);
/* only do this so out of range values are not displayed */
- CLAMP(final, -1.0f, 1.0f);
+ if (is_constrained) {
+ CLAMP(final, -1.0f, 1.0f);
+ }
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
+ /* header string */
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
-
outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"),
- &c[0], WM_bool_as_string(!is_proportional));
- }
- else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
- &c[0], WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
- }
- }
- else if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s"),
- final, WM_bool_as_string(!is_proportional));
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
- final, WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
-
- CLAMP(final, -1.0f, 1.0f);
-
- t->values[0] = final;
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
+ if (!is_proportional) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ }
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ /* done with header string */
/* do stuff here */
doEdgeSlide(t, final);
@@ -6432,10 +6842,20 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
{
VertSlideData *sld = t->customData;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
- const float *co_orig = sv->co_orig_2d;
- const float *co_curr = sv->co_link_orig_2d[sv->co_link_curr];
- const int mval_start[2] = {co_orig[0], co_orig[1]};
- const int mval_end[2] = {co_curr[0], co_curr[1]};
+
+ const float *co_orig_3d = sv->co_orig_3d;
+ const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr];
+
+ float co_curr_2d[2], co_orig_2d[2];
+
+ int mval_ofs[2], mval_start[2], mval_end[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat);
+ ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat);
+
+ ARRAY_SET_ITEMS(mval_ofs, t->imval[0] - co_orig_2d[0], t->imval[1] - co_orig_2d[1]);
+ ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
+ ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
if (sld->flipped_vtx && sld->is_proportional == false) {
setCustomPoints(t, &t->mouse, mval_start, mval_end);
@@ -6443,6 +6863,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
else {
setCustomPoints(t, &t->mouse, mval_end, mval_start);
}
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
}
/**
@@ -6460,28 +6885,39 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
int i;
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
- dist_sq = len_squared_v2v2(mval_fl, sv->co_orig_2d);
+ float co_2d[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat);
+
+ dist_sq = len_squared_v2v2(mval_fl, co_2d);
if (dist_sq < dist_min_sq) {
dist_min_sq = dist_sq;
sld->curr_sv_index = i;
}
}
}
+
/**
* Run while moving the mouse to slide along the edge matching the mouse direction
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
VertSlideData *sld = t->customData;
- float mval_fl[2] = {UNPACK2(mval)};
+ float imval_fl[2] = {UNPACK2(t->imval)};
+ float mval_fl[2] = {UNPACK2(mval)};
- float dir[2];
+ float dir[3];
TransDataVertSlideVert *sv;
int i;
- /* first get the direction of the original vertex */
- sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl);
- normalize_v2(dir);
+ /* first get the direction of the original mouse position */
+ sub_v2_v2v2(dir, imval_fl, mval_fl);
+ ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac);
+
+ invert_m4_m4(t->obedit->imat, t->obedit->obmat);
+ mul_mat3_m4_v3(t->obedit->imat, dir);
+
+ normalize_v3(dir);
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
if (sv->co_link_tot > 1) {
@@ -6490,11 +6926,14 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
int j;
for (j = 0; j < sv->co_link_tot; j++) {
- float tdir[2];
+ float tdir[3];
float dir_dot;
- sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]);
- normalize_v2(tdir);
- dir_dot = dot_v2v2(dir, tdir);
+
+ sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
+ project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
+
+ normalize_v3(tdir);
+ dir_dot = dot_v3v3(dir, tdir);
if (dir_dot > dir_dot_best) {
dir_dot_best = dir_dot;
co_link_curr_best = j;
@@ -6518,32 +6957,14 @@ static bool createVertSlideVerts(TransInfo *t)
BMVert *v;
TransDataVertSlideVert *sv_array;
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
-// View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
- float projectMat[4][4];
int j;
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
-// v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = ar ? ar->regiondata : NULL;
- }
-
slide_origdata_init_flag(t, &sld->orig_data);
sld->is_proportional = true;
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
- }
-
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
bool ok = false;
@@ -6587,7 +7008,6 @@ static bool createVertSlideVerts(TransInfo *t)
}
sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__);
- sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__);
sv_array[j].co_link_tot = k;
k = 0;
@@ -6595,31 +7015,9 @@ static bool createVertSlideVerts(TransInfo *t)
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMVert *v_other = BM_edge_other_vert(e, v);
copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_link_orig_3d[k],
- sv_array[j].co_link_orig_2d[k],
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_link_orig_2d[k],
- sv_array[j].co_link_orig_3d[k]);
- }
k++;
}
}
-
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_orig_3d,
- sv_array[j].co_orig_2d,
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_orig_2d,
- sv_array[j].co_orig_3d);
- }
-
j++;
}
}
@@ -6637,7 +7035,19 @@ static bool createVertSlideVerts(TransInfo *t)
t->customData = sld;
- if (rv3d) {
+ /* most likely will be set below */
+ unit_m4(sld->proj_mat);
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* view vars */
+ RegionView3D *rv3d = NULL;
+ ARegion *ar = t->ar;
+
+ rv3d = ar ? ar->regiondata : NULL;
+ if (rv3d) {
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+ }
+
calcVertSlideMouseActiveVert(t, t->mval);
calcVertSlideMouseActiveEdges(t, t->mval);
}
@@ -6677,7 +7087,6 @@ void freeVertSlideVerts(TransInfo *t)
TransDataVertSlideVert *sv = sld->sv;
int i = 0;
for (i = 0; i < sld->totsv; i++, sv++) {
- MEM_freeN(sv->co_link_orig_2d);
MEM_freeN(sv->co_link_orig_3d);
}
}
@@ -6744,16 +7153,13 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
sld->flipped_vtx = !sld->flipped_vtx;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case CKEY:
- {
/* use like a modifier key */
if (event->val == KM_PRESS) {
t->flag ^= T_ALT_TRANSFORM;
@@ -6761,23 +7167,17 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_HARD;
}
break;
- }
#if 0
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
break;
- }
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
break;
- }
}
- }
+ break;
#endif
case MOUSEMOVE:
{
@@ -6797,19 +7197,20 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawVertSlide(const struct bContext *C, TransInfo *t)
+static void drawVertSlide(TransInfo *t)
{
- if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = (VertSlideData *)t->customData;
+ if ((t->mode == TFM_VERT_SLIDE) && t->customData) {
+ VertSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld) {
- View3D *v3d = CTX_wm_view3d(C);
+ {
+ View3D *v3d = t->view;
TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
TransDataVertSlideVert *sv;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
const int alpha_shade = -160;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
int i;
if (v3d && v3d->zbuf)
@@ -6857,11 +7258,40 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t)
curr_sv->co_orig_3d);
bglEnd();
+ glDisable(GL_BLEND);
+
+ /* direction from active vertex! */
+ if ((t->mval[0] != t->imval[0]) ||
+ (t->mval[1] != t->imval[1]))
+ {
+ float zfac = ED_view3d_calc_zfac(t->ar->regiondata, curr_sv->co_orig_3d, NULL);
+ float mval_ofs[2];
+ float co_dest_3d[3];
+
+ mval_ofs[0] = t->mval[0] - t->imval[0];
+ mval_ofs[1] = t->mval[1] - t->imval[1];
+
+ ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
+
+ invert_m4_m4(t->obedit->imat, t->obedit->obmat);
+ mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+
+ add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
+
+ glLineWidth(1);
+ setlinestyle(1);
+
+ cpack(0xffffff);
+ glBegin(GL_LINES);
+ glVertex3fv(curr_sv->co_orig_3d);
+ glVertex3fv(co_dest_3d);
+
+ glEnd();
+ }
+
glPopMatrix();
glPopAttrib();
- glDisable(GL_BLEND);
-
if (v3d && v3d->zbuf)
glEnable(GL_DEPTH_TEST);
}
@@ -6933,6 +7363,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
/* header string */
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
@@ -7001,6 +7433,8 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
applyNumInput(&t->num, &final);
+ t->values[0] = final;
+
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
@@ -7273,7 +7707,7 @@ static void initSeqSlide(TransInfo *t)
t->num.idx_max = t->idx_max;
t->snap[0] = 0.0f;
- t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
+ t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
t->snap[2] = 10.0f;
copy_v3_fl(t->num.val_inc, t->snap[1]);
@@ -7307,40 +7741,28 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
-static void applySeqSlideValue(TransInfo *t, const float val[2], int frame)
+static void applySeqSlideValue(TransInfo *t, const float val[2])
{
TransData *td = t->data;
int i;
- TransSeq *ts = t->customData;
for (i = 0; i < t->total; i++, td++) {
- float tvec[2];
-
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- copy_v2_v2(tvec, val);
-
- mul_v2_fl(tvec, td->factor);
-
- if (t->modifiers & MOD_SNAP_INVERT) {
- td->loc[0] = frame + td->factor * (td->iloc[0] - ts->min);
- }
- else {
- td->loc[0] = td->iloc[0] + tvec[0];
- }
-
- td->loc[1] = td->iloc[1] + tvec[1];
+ madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
}
}
static void applySeqSlide(TransInfo *t, const int mval[2])
{
char str[MAX_INFO_LEN];
- int snap_frame = 0;
+
+ snapSequenceBounds(t, mval);
+
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
@@ -7348,16 +7770,15 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
copy_v3_v3(t->values, tvec);
}
else {
- snap_frame = snapSequenceBounds(t, mval);
// snapGridIncrement(t, t->values);
applyNumInput(&t->num, t->values);
}
- t->values[0] = floor(t->values[0] + 0.5f);
- t->values[1] = floor(t->values[1] + 0.5f);
+ t->values[0] = floorf(t->values[0] + 0.5f);
+ t->values[1] = floorf(t->values[1] + 0.5f);
headerSeqSlide(t, t->values, str);
- applySeqSlideValue(t, t->values, snap_frame);
+ applySeqSlideValue(t, t->values);
recalcData(t);
@@ -7520,6 +7941,7 @@ static void initTimeTranslate(TransInfo *t)
static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
+ int ofs = 0;
/* if numeric input is active, use results from that, otherwise apply snapping to result */
if (hasNumInput(&t->num)) {
@@ -7555,10 +7977,14 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ }
}
-static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
+static void applyTimeTranslateValue(TransInfo *t)
{
TransData *td = t->data;
TransData2D *td2d = t->data2d;
@@ -7588,11 +8014,11 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- deltax = (float)(floor(deltax + 0.5f));
+ deltax = floorf(deltax + 0.5f);
}
val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
- val += deltax;
+ val += deltax * td->factor;
*(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
}
else {
@@ -7602,7 +8028,7 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- val = (float)(floor(val + 0.5f));
+ val = floorf(val + 0.5f);
}
*(td->val) = td->ival + val;
@@ -7616,15 +8042,17 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- float cval[2], sval[2];
char str[MAX_INFO_LEN];
/* calculate translation amount from mouse movement - in 'time-grid space' */
- UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
+ if (t->flag & T_MODAL) {
+ float cval[2], sval[2];
+ UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
+ UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
- /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
- t->values[0] = cval[0] - sval[0];
+ /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+ t->values[0] = cval[0] - sval[0];
+ }
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -7632,7 +8060,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
t->values[0] = t->vec[0];
headerTimeTranslate(t, str);
- applyTimeTranslateValue(t, sval[0]);
+ applyTimeTranslateValue(t);
recalcData(t);
@@ -7765,7 +8193,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
/* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */
// XXX Need to be able to repeat this
- t->values[0] = cval[0];
+ /* t->values[0] = cval[0]; */ /* UNUSED (reset again later). */
/* handle numeric-input stuff */
t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
@@ -7866,7 +8294,7 @@ static void applyTimeScaleValue(TransInfo *t)
fac = (float)(floor((double)fac / secf + 0.5) * secf);
}
else if (autosnap == SACTSNAP_STEP) {
- fac = (float)(floor(fac + 0.5f));
+ fac = floorf(fac + 0.5f);
}
/* check if any need to apply nla-mapping */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 8d6c693b14a..8863d337cff 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -39,9 +39,6 @@
#include "DNA_listBase.h"
-#include "BLI_smallhash.h"
-#include "BKE_editmesh.h"
-
/* ************************** Types ***************************** */
struct TransInfo;
@@ -107,8 +104,6 @@ typedef struct TransCon {
float mtx[3][3]; /* Matrix of the Constraint space */
float imtx[3][3]; /* Inverse Matrix of the Constraint space */
float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */
- float center[3]; /* transformation center to define where to draw the view widget
- * ALWAYS in global space. Unlike the transformation center */
int imval[2]; /* initial mouse value for visual calculation */
/* the one in TransInfo is not garanty to stay the same (Rotates change it) */
int mode; /* Mode flags of the Constraint */
@@ -216,10 +211,10 @@ typedef struct TransDataEdgeSlideVert {
float edge_len;
- struct BMVert *v_a, *v_b;
+ struct BMVert *v_side[2];
/* add origvert.co to get the original locations */
- float dir_a[3], dir_b[3];
+ float dir_side[2][3];
int loop_nr;
} TransDataEdgeSlideVert;
@@ -256,19 +251,20 @@ typedef struct EdgeSlideData {
bool flipped_vtx;
int curr_sv_index;
+
+ /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
+ int curr_side_unclamp;
} EdgeSlideData;
typedef struct TransDataVertSlideVert {
/* TransDataGenericSlideVert */
- BMVert *v;
+ struct BMVert *v;
struct LinkNode **cd_loop_groups;
float co_orig_3d[3];
/* end generic */
- float co_orig_2d[2];
float (*co_link_orig_3d)[3];
- float (*co_link_orig_2d)[2];
int co_link_tot;
int co_link_curr;
} TransDataVertSlideVert;
@@ -287,6 +283,9 @@ typedef struct VertSlideData {
bool flipped_vtx;
int curr_sv_index;
+
+ /* result of ED_view3d_ob_project_mat_get */
+ float proj_mat[4][4];
} VertSlideData;
typedef struct BoneInitData {
@@ -356,7 +355,10 @@ typedef struct TransInfo {
eRedrawFlag redraw; /* redraw flag */
float prop_size; /* proportional circle radius */
char proptext[20]; /* proportional falloff text */
- float center[3]; /* center of transformation */
+ float aspect[3]; /* spaces using non 1:1 aspect, (uv's, f-curve, movie-clip... etc)
+ * use for conversion and snapping. */
+ float center[3]; /* center of transformation (in local-space) */
+ float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
int imval[2]; /* initial mouse position */
short event_type; /* event->type used to invoke transform */
@@ -541,6 +543,7 @@ void transformApply(struct bContext *C, TransInfo *t);
int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
+void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy);
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
@@ -626,7 +629,7 @@ typedef enum {
void snapGridIncrement(TransInfo *t, float *val);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action);
-int snapSequenceBounds(TransInfo *t, const int mval[2]);
+void snapSequenceBounds(TransInfo *t, const int mval[2]);
bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
@@ -690,6 +693,7 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
+void calculateCenterGlobal(TransInfo *t);
void calculateCenter(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index ccb81c7342b..3063ee22c55 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -46,6 +46,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
@@ -202,7 +203,7 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
return;
}
- copy_v3_v3(t_con_center, t->con.center);
+ copy_v3_v3(t_con_center, t->center_global);
/* checks for center being too close to the view center */
viewAxisCorrectCenter(t, t_con_center);
@@ -276,7 +277,7 @@ static void planeProjection(TransInfo *t, const float in[3], float out[3])
{
float vec[3], factor, norm[3];
- add_v3_v3v3(vec, in, t->con.center);
+ add_v3_v3v3(vec, in, t->center_global);
getViewVector(t, vec, norm);
sub_v3_v3v3(vec, out, in);
@@ -309,7 +310,7 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
mul_m3_v3(t->con.pmtx, out);
// With snap, a projection is alright, no need to correct for view alignment
- if (!(t->tsnap.mode != SCE_SNAP_MODE_INCREMENT && activeSnap(t))) {
+ if (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) || activeSnap(t)) {
if (getConstraintSpaceDimension(t) == 2) {
if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
planeProjection(t, in, out);
@@ -687,11 +688,11 @@ void drawConstraint(TransInfo *t)
int depth_test_enabled;
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
- add_v3_v3(vec, tc->center);
+ add_v3_v3(vec, t->center_global);
- drawLine(t, tc->center, tc->mtx[0], 'X', 0);
- drawLine(t, tc->center, tc->mtx[1], 'Y', 0);
- drawLine(t, tc->center, tc->mtx[2], 'Z', 0);
+ drawLine(t, t->center_global, tc->mtx[0], 'X', 0);
+ drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
+ drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
glColor3ubv((GLubyte *)col2);
@@ -701,7 +702,7 @@ void drawConstraint(TransInfo *t)
setlinestyle(1);
glBegin(GL_LINE_STRIP);
- glVertex3fv(tc->center);
+ glVertex3fv(t->center_global);
glVertex3fv(vec);
glEnd();
setlinestyle(0);
@@ -711,13 +712,13 @@ void drawConstraint(TransInfo *t)
}
if (tc->mode & CON_AXIS0) {
- drawLine(t, tc->center, tc->mtx[0], 'X', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT);
}
if (tc->mode & CON_AXIS1) {
- drawLine(t, tc->center, tc->mtx[1], 'Y', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT);
}
if (tc->mode & CON_AXIS2) {
- drawLine(t, tc->center, tc->mtx[2], 'Z', DRAWLIGHT);
+ drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT);
}
}
}
@@ -728,7 +729,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
if (t->flag & T_PROP_EDIT) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float tmat[4][4], imat[4][4];
- float center[3];
int depth_test_enabled;
UI_ThemeColor(TH_GRID);
@@ -744,25 +744,21 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
glPushMatrix();
- copy_v3_v3(center, t->center);
-
- if ((t->spacetype == SPACE_VIEW3D) && t->obedit) {
- mul_m4_v3(t->obedit->obmat, center); /* because t->center is in local space */
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* pass */
}
else if (t->spacetype == SPACE_IMAGE) {
- float aspx, aspy;
-
- if (t->options & CTX_MASK) {
- /* untested - mask aspect is TODO */
- ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- aspx = aspy = 1.0;
- }
- else {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- }
- glScalef(1.0f / aspx, 1.0f / aspy, 1.0);
+ glScalef(1.0f / t->aspect[0], 1.0f / t->aspect[1], 1.0f);
+ }
+ else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) {
+ /* only scale y */
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+ glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f);
}
depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
@@ -770,7 +766,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
glDisable(GL_DEPTH_TEST);
set_inverted_drawing(1);
- drawcircball(GL_LINE_LOOP, center, t->prop_size, imat);
+ drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat);
set_inverted_drawing(0);
if (depth_test_enabled)
@@ -961,7 +957,7 @@ static void setNearestAxis3d(TransInfo *t)
mul_v3_fl(axis, zfac);
/* now we can project to get window coordinate */
- add_v3_v3(axis, t->con.center);
+ add_v3_v3(axis, t->center_global);
projectFloatView(t, axis, axis_2d);
sub_v2_v2v2(axis, axis_2d, t->center2d);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index b50f56aae3e..c9e7e085a96 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <math.h>
+#include <limits.h>
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
@@ -58,6 +59,7 @@
#include "BLI_linklist_stack.h"
#include "BLI_string.h"
#include "BLI_bitmap.h"
+#include "BLI_rect.h"
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
@@ -340,20 +342,20 @@ static void createTransEdge(TransInfo *t)
BMIter iter;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int cd_edge_float_offset;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
}
if (countsel == 0)
return;
- if (propmode) {
+ if (is_prop_edit) {
t->total = count;
}
else {
@@ -379,7 +381,7 @@ static void createTransEdge(TransInfo *t)
BLI_assert(cd_edge_float_offset != -1);
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || propmode)) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
float *fl_ptr;
/* need to set center for center calculations */
mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
@@ -627,10 +629,10 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
bArmature *arm = t->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &bone->dist;
td->ival = bone->dist;
@@ -717,7 +719,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* make sure no bone can be transformed when a parent is transformed */
/* since pchans are depsgraph sorted, the parents are in beginning of list */
- if (mode != TFM_BONESIZE) {
+ if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
if (bone->flag & BONE_TRANSFORM)
@@ -1124,7 +1126,7 @@ static void createTransArmatureVerts(TransInfo *t)
oldtot = t->total;
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED)
t->total++;
}
@@ -1202,9 +1204,9 @@ static void createTransArmatureVerts(TransInfo *t)
}
}
- else if (t->mode == TFM_BONESIZE) {
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED) {
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &ebo->dist;
td->ival = ebo->dist;
@@ -1329,18 +1331,18 @@ static void createTransMBallVerts(TransInfo *t)
TransDataExtension *tx;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
/* count totals */
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
@@ -1350,7 +1352,7 @@ static void createTransMBallVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (propmode || (ml->flag & SELECT)) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
td->loc = &ml->x;
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->center, td->loc);
@@ -1463,7 +1465,7 @@ static void createTransCurveVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
ListBase *nurbs;
@@ -1478,13 +1480,13 @@ static void createTransCurveVerts(TransInfo *t)
if (bezt->hide == 0) {
if (hide_handles) {
if (bezt->f2 & SELECT) countsel += 3;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
else {
if (bezt->f1 & SELECT) countsel++;
if (bezt->f2 & SELECT) countsel++;
if (bezt->f3 & SELECT) countsel++;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
}
}
@@ -1492,7 +1494,7 @@ static void createTransCurveVerts(TransInfo *t)
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode) count++;
+ if (is_prop_edit) count++;
if (bp->f1 & SELECT) countsel++;
}
}
@@ -1501,7 +1503,7 @@ static void createTransCurveVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
@@ -1536,7 +1538,7 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f1 & SELECT) && hide_handles == 0))
{
@@ -1570,7 +1572,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (propmode || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || (bezt->f2 & SELECT)) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1606,7 +1608,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f3 & SELECT) && hide_handles == 0))
{
@@ -1643,12 +1645,12 @@ static void createTransCurveVerts(TransInfo *t)
(void)hdata; /* quiet warning */
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
/* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
@@ -1663,7 +1665,7 @@ static void createTransCurveVerts(TransInfo *t)
head = tail = td;
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1688,12 +1690,12 @@ static void createTransCurveVerts(TransInfo *t)
tail++;
}
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1709,14 +1711,14 @@ static void createTransLatticeVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
if (bp->hide == 0) {
if (bp->f1 & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
bp++;
}
@@ -1724,7 +1726,7 @@ static void createTransLatticeVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
@@ -1735,7 +1737,7 @@ static void createTransLatticeVerts(TransInfo *t)
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
if (bp->hide == 0) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
@@ -1776,7 +1778,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
float mat[4][4];
int i, k, transformparticle;
int count = 0, hasselected = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
@@ -1798,7 +1800,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
hasselected = 1;
transformparticle = 1;
}
- else if (propmode)
+ else if (is_prop_edit)
transformparticle = 1;
}
}
@@ -1848,7 +1850,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (key->flag & PEK_SELECT)
td->flag |= TD_SELECTED;
- else if (!propmode)
+ else if (!is_prop_edit)
td->flag |= TD_SKIP;
unit_m3(td->mtx);
@@ -1877,7 +1879,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
tx++;
tail++;
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1893,7 +1895,8 @@ void flushTransParticles(TransInfo *t)
PTCacheEditKey *key;
TransData *td;
float mat[4][4], imat[4][4], co[3];
- int i, k, propmode = t->flag & T_PROP_EDIT;
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (psys)
psmd = psys_get_modifier(ob, psys);
@@ -1914,7 +1917,7 @@ void flushTransParticles(TransInfo *t)
/* optimization for proportional edit */
- if (!propmode || !compare_v3v3(key->co, co, 0.0001f)) {
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
copy_v3_v3(key->co, co);
point->flag |= PEP_EDIT_RECALC;
}
@@ -1972,17 +1975,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
int i;
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
BM_elem_index_set(v, i); /* set_inline */
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dists[i] = FLT_MAX;
+ dist = FLT_MAX;
}
else {
BLI_LINKSTACK_PUSH(queue, v);
-
- dists[i] = 0.0f;
+ dist = 0.0f;
}
+
+ dists[i] = dists_prev[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
@@ -1991,55 +1996,77 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BMVert *v;
LinkNode *lnk;
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
while ((v = BLI_LINKSTACK_POP(queue))) {
- /* quick checks */
- bool has_edges = (v->e != NULL);
- bool has_faces = false;
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
/* connected edge-verts */
- if (has_edges) {
- BMIter iter;
- BMEdge *e;
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- has_faces |= (BM_edge_is_wire(e) == false);
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+
+ /* 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 (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);
}
}
- }
- }
- }
-
- /* imaginary edge diagonally across quad */
- if (has_faces) {
- BMIter iter;
- BMLoop *l;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len == 4)) {
- BMVert *v_other = l->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_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);
- }
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) &&
+ (l_iter_radial->f->len == 4) &&
+ (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 (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);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
}
}
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
}
}
+
/* clear for the next loop */
for (lnk = queue_next; lnk; lnk = lnk->next) {
- BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
+ BMVert *v = lnk->link;
+ const int i = BM_elem_index_get(v);
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2097,7 +2124,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
* its possible we have a selected vertex thats not in a face, for now best not crash in that case. */
- fill_vn_i(vert_map, bm->totvert, -1);
+ copy_vn_i(vert_map, bm->totvert, -1);
BM_mesh_elem_table_ensure(bm, htype);
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
@@ -2257,7 +2284,7 @@ static void createTransEditVerts(TransInfo *t)
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
float *dists = NULL;
int a;
- int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int mirror = 0;
int cd_vert_bweight_offset = -1;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -2297,7 +2324,7 @@ static void createTransEditVerts(TransInfo *t)
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
- if (propmode) {
+ if (prop_mode) {
unsigned int count = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@@ -2308,7 +2335,7 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (propmode & T_PROP_CONNECTED)
+ if (prop_mode & T_PROP_CONNECTED)
dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
}
else {
@@ -2330,7 +2357,7 @@ static void createTransEditVerts(TransInfo *t)
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode & T_PROP_CONNECTED) {
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
@@ -2359,7 +2386,7 @@ static void createTransEditVerts(TransInfo *t)
{
mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !propmode);
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
MEM_freeN(mappedcos);
}
@@ -2384,7 +2411,7 @@ 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 (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ 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;
float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
@@ -2397,8 +2424,8 @@ static void createTransEditVerts(TransInfo *t)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
tob->flag |= TD_SELECTED;
- if (propmode) {
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
tob->dist = dists[a];
}
else {
@@ -2650,24 +2677,23 @@ void flushTransSeq(TransInfo *t)
/* ********************* UV ****************** */
-static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected)
+static void UVsToTransData(
+ const float aspect[2], TransData *td, TransData2D *td2d,
+ float *uv, const float *center, bool selected)
{
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
-
/* uv coords are scaled by aspects. this is needed for rotations and
* proportional editing to be consistent with the stretched uv coords
* that are displayed. this also means that for display and numinput,
* and when the uv coords are flushed, these are converted each time */
- td2d->loc[0] = uv[0] * aspx;
- td2d->loc[1] = uv[1] * aspy;
+ td2d->loc[0] = uv[0] * aspect[0];
+ td2d->loc[1] = uv[1] * aspect[1];
td2d->loc[2] = 0.0f;
td2d->loc2d = uv;
td->flag = 0;
td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
+ copy_v2_v2(td->center, center ? center : td->loc);
+ td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
memset(td->axismtx, 0, sizeof(td->axismtx));
@@ -2694,36 +2720,43 @@ static void createTransUVs(bContext *C, TransInfo *t)
ToolSettings *ts = CTX_data_tool_settings(C);
TransData *td = NULL;
TransData2D *td2d = NULL;
- MTexPoly *tf;
- MLoopUV *luv;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMFace *efa;
- BMLoop *l;
BMIter iter, liter;
UvElementMap *elementmap = NULL;
BLI_bitmap *island_enabled = NULL;
+ struct { float co[2]; int co_num; } *island_center = NULL;
int count = 0, countsel = 0, count_rejected = 0;
- const bool propmode = (t->flag & T_PROP_EDIT) != 0;
- const bool propconnected = (t->flag & T_PROP_CONNECTED) != 0;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_LOCAL);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- if (!ED_space_image_show_uvedit(sima, t->obedit)) return;
+ if (!ED_space_image_show_uvedit(sima, t->obedit))
+ return;
/* count */
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
/* create element map with island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- elementmap = BM_uv_element_map_create(em->bm, false, true);
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
}
- else {
- elementmap = BM_uv_element_map_create(em->bm, true, true);
+
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
+
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
}
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ BMLoop *l;
if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
@@ -2735,14 +2768,25 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
countsel++;
- if (propconnected) {
+ if (is_prop_connected || island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
+ }
+ }
}
- if (propmode) {
+ if (is_prop_edit) {
count++;
}
}
@@ -2750,13 +2794,19 @@ static void createTransUVs(bContext *C, TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) {
- if (propconnected) {
- MEM_freeN(island_enabled);
+ goto finally;
+ }
+
+ if (is_island_center) {
+ int i;
+
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
}
- return;
}
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -2769,56 +2819,88 @@ static void createTransUVs(bContext *C, TransInfo *t)
td2d = t->data2d;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!propmode && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
+
+ if (!is_prop_edit && !selected)
continue;
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
+
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
+ }
+
+ if (is_island_center) {
+ center = island_center[element->island].co;
}
}
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
}
}
- if (propconnected) {
+ if (is_prop_connected) {
t->total -= count_rejected;
- BM_uv_element_map_free(elementmap);
- MEM_freeN(island_enabled);
}
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
+
+
+finally:
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
+
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
+
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
+ }
}
void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->sa->spacedata.first;
TransData2D *td;
- int a, width, height;
- float aspx, aspy, invx, invy;
+ int a;
+ float aspect_inv[2], size[2];
+ const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- ED_space_image_get_size(sima, &width, &height);
- invx = 1.0f / aspx;
- invy = 1.0f / aspy;
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
+
+ if (use_pixel_snap) {
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
/* flush to 2d vector from internally used 3d vector */
for (a = 0, td = t->data2d; a < t->total; a++, td++) {
- td->loc2d[0] = td->loc[0] * invx;
- td->loc2d[1] = td->loc[1] * invy;
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
- if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
- td->loc2d[0] = roundf(width * td->loc2d[0]) / width;
- td->loc2d[1] = roundf(height * td->loc2d[1]) / height;
+ if (use_pixel_snap) {
+ td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
+ td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
}
}
}
@@ -2826,44 +2908,45 @@ void flushTransUVs(TransInfo *t)
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
TransData *td;
- int a, clipx = 1, clipy = 1;
- float aspx, aspy, min[2], max[2];
+ int a;
+ bool clipx = true, clipy = true;
+ float min[2], max[2];
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
min[0] = min[1] = 0.0f;
- max[0] = aspx; max[1] = aspy;
+ max[0] = t->aspect[0];
+ max[1] = t->aspect[1];
for (a = 0, td = t->data; a < t->total; a++, td++) {
minmax_v2v2_v2(min, max, td->loc);
}
if (resize) {
- if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx * 0.5f)
+ if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
vec[0] *= t->center[0] / (t->center[0] - min[0]);
- else if (max[0] > aspx && t->center[0] < aspx)
- vec[0] *= (t->center[0] - aspx) / (t->center[0] - max[0]);
+ else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
+ vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
else
clipx = 0;
- if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy * 0.5f)
+ if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
vec[1] *= t->center[1] / (t->center[1] - min[1]);
- else if (max[1] > aspy && t->center[1] < aspy)
- vec[1] *= (t->center[1] - aspy) / (t->center[1] - max[1]);
+ else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
+ vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
else
clipy = 0;
}
else {
if (min[0] < 0.0f)
vec[0] -= min[0];
- else if (max[0] > aspx)
- vec[0] -= max[0] - aspx;
+ else if (max[0] > t->aspect[0])
+ vec[0] -= max[0] - t->aspect[0];
else
clipx = 0;
if (min[1] < 0.0f)
vec[1] -= min[1];
- else if (max[1] > aspy)
- vec[1] -= max[1] - aspy;
+ else if (max[1] > t->aspect[1])
+ vec[1] -= max[1] - t->aspect[1];
else
clipy = 0;
}
@@ -2875,9 +2958,6 @@ void clipUVData(TransInfo *t)
{
TransData *td = NULL;
int a;
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
for (a = 0, td = t->data; a < t->total; a++, td++) {
if (td->flag & TD_NOACTION)
@@ -2886,8 +2966,8 @@ void clipUVData(TransInfo *t)
if ((td->flag & TD_SKIP) || (!td->loc))
continue;
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), aspx);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), aspy);
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
}
}
@@ -3161,7 +3241,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
bGPDframe *gpf, *gpfn;
bool is_double = false;
- BLI_listbase_sort_r(&gpl->frames, &is_double, gpf_cmp_frame);
+ BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
if (is_double) {
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
@@ -3188,7 +3268,7 @@ static void posttrans_mask_clean(Mask *mask)
MaskLayerShape *masklay_shape, *masklay_shape_next;
bool is_double = false;
- BLI_listbase_sort_r(&masklay->splines_shapes, &is_double, masklay_shape_cmp_frame);
+ BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
if (is_double) {
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape_next) {
@@ -3304,76 +3384,90 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* ----------------------------- */
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
{
BezTriple *bezt;
- int i, count = 0;
+ int i, count = 0, count_all = 0;
if (ELEM(NULL, fcu, fcu->bezt))
return count;
/* only include points that occur on the right side of cfra */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (bezt->f2 & SELECT) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* no need to adjust the handle selection since they are assumed
* selected (like graph editor with SIPO_NOHANDLES) */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- count += 1;
- }
+ if (bezt->f2 & SELECT)
+ count++;
+
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
{
bGPDframe *gpf;
- int count = 0;
+ int count = 0, count_all = 0;
if (gpl == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra))
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra)
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
{
MaskLayerShape *masklayer_shape;
- int count = 0;
+ int count = 0, count_all = 0;
if (masklay == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; masklayer_shape = masklayer_shape->next) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra))
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt)
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = time;
td->ival = *(time);
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
/* store the AnimData where this keyframe exists as a keyframe of the
* active action as td->extra.
*/
@@ -3387,7 +3481,7 @@ static void TimeToTransData(TransData *td, float *time, AnimData *adt)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra)
+static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos)
{
BezTriple *bezt;
TransData2D *td2d = *td2dv;
@@ -3398,11 +3492,14 @@ static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FC
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
- if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt);
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+ if (bezt->f2 & SELECT)
+ td->flag |= TD_SELECTED;
+
/*set flags to move handles as necessary*/
td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
td2d->h1 = bezt->vec[0];
@@ -3453,19 +3550,22 @@ void flushTransIntFrameActionData(TransInfo *t)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra)
+static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
{
bGPDframe *gpf;
int count = 0;
/* check for select frames on right side of current frame */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)gpf->framenum;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
@@ -3481,19 +3581,22 @@ static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl,
}
/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra)
+static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos)
{
MaskLayerShape *masklay_shape;
int count = 0;
/* check for select frames on right side of current frame */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)masklay_shape->frame;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)masklay_shape->frame;
tfd->sdata = &masklay_shape->frame;
@@ -3515,15 +3618,25 @@ static void createTransActionData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
tGPFtransdata *tfd = NULL;
-
+
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
int count = 0;
float cfra;
-
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3551,7 +3664,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
-
+ int adt_count = 0;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3560,14 +3673,19 @@ static void createTransActionData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- if (ale->type == ANIMTYPE_FCURVE)
- count += count_fcurve_keys(ale->key_data, t->frame_side, cfra);
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_GPLAYER)
- count += count_gplayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_MASKLAYER)
- count += count_masklayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else
BLI_assert(0);
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3604,11 +3722,22 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ if (is_prop_edit && !ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
int i;
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra);
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3616,7 +3745,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
MaskLayer *masklay = (MaskLayer *)ale->data;
int i;
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra);
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3624,15 +3753,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra);
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
}
}
@@ -3661,6 +3782,109 @@ static void createTransActionData(bContext *C, TransInfo *t)
*((float *)(t->customData) + 1) = max;
}
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter; masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min)
+ min = val;
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -3669,6 +3893,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
typedef struct TransDataGraph {
float unit_scale;
+ float offset;
} TransDataGraph;
/* Helper function for createTransGraphEditData, which is responsible for associating
@@ -3677,7 +3902,7 @@ typedef struct TransDataGraph {
static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *tdg,
AnimData *adt, BezTriple *bezt,
int bi, bool selected, bool ishandle, bool intvals,
- float mtx[3][3], float smtx[3][3], float unit_scale)
+ float mtx[3][3], float smtx[3][3], float unit_scale, float offset)
{
float *loc = bezt->vec[bi];
const float *cent = bezt->vec[1];
@@ -3691,26 +3916,26 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = cent[1] * unit_scale;
+ td->center[1] = (cent[1] + offset) * unit_scale;
td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
}
else {
td2d->loc[0] = loc[0];
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
copy_v3_v3(td->center, cent);
- td->center[1] *= unit_scale;
+ td->center[1] = (td->center[1] + offset) * unit_scale;
copy_v3_v3(td->iloc, td->loc);
}
@@ -3750,6 +3975,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
copy_m3_m3(td->smtx, smtx);
tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
}
static bool graph_edit_is_translation_mode(TransInfo *t)
@@ -3762,6 +3988,29 @@ static bool graph_edit_use_local_center(TransInfo *t)
return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
}
+
+static void graph_key_shortest_dist(TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
static void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
@@ -3784,6 +4033,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
/* determine what type of data we are operating on */
@@ -3815,6 +4065,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float cfra;
+ int curvecount = 0;
+ bool selected = false;
/* F-Curve may not have any keyframes */
if (fcu->bezt == NULL)
@@ -3835,20 +4087,34 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- count++;
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3)
+ selected = true;
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
+
+ if (sel3) {
+ count++;
+ }
}
- if (sel3) {
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
count++;
}
}
+ }
+ }
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- count++;
- }
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
}
}
}
@@ -3897,11 +4163,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
- float unit_scale;
+ float unit_scale, offset;
float cfra;
/* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0))
continue;
/* convert current-frame to action-time (slightly less accurate, especially under
@@ -3912,7 +4178,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -3924,66 +4190,135 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
TransDataCurveHandleFlags *hdata = NULL;
/* short h1=1, h2=1; */ /* UNUSED */
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
}
- else {
- /* h1 = 0; */ /* UNUSED */
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) td->flag |= TD_MOVEHANDLE1;
+ if (sel3) td->flag |= TD_MOVEHANDLE2;
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale, offset);
+
}
-
- if (sel3) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+ /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
+ {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0))
+ continue;
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
}
else {
- /* h2 = 0; */ /* UNUSED */
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) td->flag |= TD_MOVEHANDLE1;
- if (sel3) td->flag |= TD_MOVEHANDLE2;
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
}
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
-
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
-
- }
- /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
- {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
+ td++;
}
}
}
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
}
-
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -4267,7 +4602,7 @@ void flushTransGraphData(TransInfo *t)
if (td->flag & TD_INTVALUES)
td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
else
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale;
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
@@ -5080,7 +5415,9 @@ 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 */
@@ -5157,7 +5494,9 @@ 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 */
@@ -6039,7 +6378,7 @@ static void createTransObject(bContext *C, TransInfo *t)
TransData *td = NULL;
TransDataExtension *tx;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
set_trans_object_base_flags(t);
@@ -6052,7 +6391,7 @@ static void createTransObject(bContext *C, TransInfo *t)
return;
}
- if (propmode) {
+ if (is_prop_edit) {
t->total += count_proportional_objects(t);
}
@@ -6085,7 +6424,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
CTX_DATA_END;
- if (propmode) {
+ if (is_prop_edit) {
View3D *v3d = t->view;
Base *base;
@@ -6239,22 +6578,22 @@ typedef struct TransDataTracking {
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int area, float loc[2], float rel[2], const float off[2], float aspx, float aspy)
+ int area, float loc[2], float rel[2], const float off[2], const float aspect[2])
{
int anchor = area == TRACK_AREA_POINT && off;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
- td2d->loc[0] = rel[0] * aspx; /* hold original location */
- td2d->loc[1] = rel[1] * aspy;
+ td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = rel[1] * aspect[1];
tdt->loc = loc;
td2d->loc2d = loc; /* current location */
}
else {
- td2d->loc[0] = loc[0] * aspx; /* hold original location */
- td2d->loc[1] = loc[1] * aspy;
+ td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = loc[1] * aspect[1];
td2d->loc2d = loc; /* current location */
}
@@ -6269,8 +6608,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
if (rel) {
if (!anchor) {
- td2d->loc[0] += rel[0] * aspx;
- td2d->loc[1] += rel[1] * aspy;
+ td2d->loc[0] += rel[0] * aspect[0];
+ td2d->loc[1] += rel[1] * aspect[1];
}
copy_v2_v2(tdt->srelative, rel);
@@ -6285,8 +6624,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
//copy_v3_v3(td->center, td->loc);
td->flag |= TD_INDIVIDUAL_SCALE;
- td->center[0] = marker->pos[0] * aspx;
- td->center[1] = marker->pos[1] * aspy;
+ td->center[0] = marker->pos[0] * aspect[0];
+ td->center[1] = marker->pos[1] * aspect[1];
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
@@ -6301,8 +6640,9 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
unit_m3(td->smtx);
}
-static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d,
- TransDataTracking *tdt, MovieTrackingTrack *track, float aspx, float aspy)
+static void trackToTransData(
+ const int framenr, TransData *td, TransData2D *td2d,
+ TransDataTracking *tdt, MovieTrackingTrack *track, const float aspect[2])
{
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
@@ -6310,11 +6650,11 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- track->offset, marker->pos, track->offset, aspx, aspy);
+ track->offset, marker->pos, track->offset, aspect);
if (track->flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- marker->pos, NULL, NULL, aspx, aspy);
+ marker->pos, NULL, NULL, aspect);
}
if (track->pat_flag & SELECT) {
@@ -6322,28 +6662,28 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
for (a = 0; a < 4; a++) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_PAT,
- marker->pattern_corners[a], marker->pos, NULL, aspx, aspy);
+ marker->pattern_corners[a], marker->pos, NULL, aspect);
}
}
if (track->search_flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_min, marker->pos, NULL, aspx, aspy);
+ marker->search_min, marker->pos, NULL, aspect);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_max, marker->pos, NULL, aspx, aspy);
+ marker->search_max, marker->pos, NULL, aspect);
}
}
static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingPlaneTrack *plane_track, float corner[2],
- float aspx, float aspy)
+ const float aspect[2])
{
tdt->mode = transDataTracking_ModePlaneTracks;
tdt->plane_track = plane_track;
- td2d->loc[0] = corner[0] * aspx; /* hold original location */
- td2d->loc[1] = corner[1] * aspy;
+ td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = corner[1] * aspect[1];
td2d->loc2d = corner; /* current location */
td2d->loc[2] = 0.0f;
@@ -6368,7 +6708,7 @@ static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDa
static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d,
TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track,
- float aspx, float aspy)
+ const float aspect[2])
{
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
int i;
@@ -6377,7 +6717,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy);
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
}
}
@@ -6406,7 +6746,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
MovieTrackingPlaneTrack *plane_track;
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
- float aspx, aspy;
/* count */
t->total = 0;
@@ -6441,8 +6780,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
if (t->total == 0)
return;
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
-
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
@@ -6453,7 +6790,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, aspx, aspy);
+ trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
/* offset */
td++;
@@ -6487,7 +6824,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
plane_track = plane_track->next)
{
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy);
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
td += 4;
td2d += 4;
tdt += 4;
@@ -6699,14 +7036,10 @@ static void cancelTransTracking(TransInfo *t)
void flushTransTracking(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
int a;
- float aspx, aspy;
-
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
@@ -6720,8 +7053,8 @@ void flushTransTracking(TransInfo *t)
continue;
}
- loc2d[0] = td2d->loc[0] / aspx;
- loc2d[1] = td2d->loc[1] / aspy;
+ loc2d[0] = td2d->loc[0] / t->aspect[0];
+ loc2d[1] = td2d->loc[1] / t->aspect[1];
if (t->flag & T_ALT_TRANSFORM) {
if (t->mode == TFM_RESIZE) {
@@ -6763,8 +7096,8 @@ void flushTransTracking(TransInfo *t)
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- td2d->loc2d[0] = td2d->loc[0] / aspx;
- td2d->loc2d[1] = td2d->loc[1] / aspy;
+ td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
+ td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
}
}
}
@@ -6842,9 +7175,10 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which
}
}
-static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
- TransData *td, TransData2D *td2d, TransDataMasking *tdm,
- const int propmode, const float asp[2])
+static void MaskPointToTransData(
+ Scene *scene, MaskSplinePoint *point,
+ TransData *td, TransData2D *td2d, TransDataMasking *tdm,
+ const bool is_prop_edit, const float asp[2])
{
BezTriple *bezt = &point->bezt;
const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
@@ -6854,7 +7188,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
- if (propmode || is_sel_point) {
+ if (is_prop_edit || is_sel_point) {
int i;
tdm->point = point;
@@ -6974,7 +7308,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
TransData2D *td2d = NULL;
TransDataMasking *tdm = NULL;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
t->total = 0;
@@ -7024,7 +7358,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
}
}
- if (propmode)
+ if (is_prop_edit)
count += 3;
}
}
@@ -7037,7 +7371,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -7060,10 +7394,10 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (propmode || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp);
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
- if (propmode || MASKPOINT_ISSEL_KNOT(point)) {
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
td += 3;
td2d += 3;
tdm += 3;
@@ -7306,8 +7640,8 @@ static void createTransGPencil(bContext *C, TransInfo *t)
const Scene *scene = CTX_data_scene(C);
const int cfra = CFRA;
- const int propedit = (t->flag & T_PROP_EDIT);
- const int propedit_connected = (t->flag & T_PROP_CONNECTED);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
/* == Grease Pencil Strokes to Transform Data ==
@@ -7338,9 +7672,9 @@ static void createTransGPencil(bContext *C, TransInfo *t)
continue;
}
- if (propedit) {
+ if (is_prop_edit) {
/* Proportional Editing... */
- if (propedit_connected) {
+ if (is_prop_edit_connected) {
/* connected only - so only if selected */
if (gps->flag & GP_STROKE_SELECT)
t->total += gps->totpoints;
@@ -7447,8 +7781,8 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
/* What we need to include depends on proportional editing settings... */
- if (propedit) {
- if (propedit_connected) {
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
/* A) "Connected" - Only those in selected strokes */
stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
}
@@ -7467,7 +7801,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
bGPDspoint *pt;
int i;
-#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or propedit breaks */
+#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
const float ninv = 1.0f / gps->totpoints;
float center[3] = {0.0f};
@@ -7482,7 +7816,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
bool point_ok;
/* include point? */
- if (propedit) {
+ if (is_prop_edit) {
/* Always all points in strokes that get included */
point_ok = true;
}
@@ -7525,7 +7859,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
/* March over these points, and calculate the proportional editing distances */
- if (propedit && (head != tail)) {
+ if (is_prop_edit && (head != tail)) {
/* XXX: for now, we are similar enough that this works... */
calc_distanceCurveVerts(head, tail - 1);
}
@@ -7594,6 +7928,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransActionData(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ //set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
+ sort_trans_data_dist(t);
+ }
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
@@ -7607,13 +7947,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransGraphEditData(C, t);
-#if 0
+
if (t->data && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 1);
+ set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
}
-#endif
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 5f02fa1b05f..90c806a2d05 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -80,6 +80,7 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
+#include "BKE_utildefines.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -808,10 +809,14 @@ static void recalcData_objects(TransInfo *t)
ebo->rad_head *= ebo->length / ebo->oldlength;
ebo->rad_tail *= ebo->length / ebo->oldlength;
ebo->oldlength = ebo->length;
+
+ if (ebo_parent) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
}
}
- if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
/* fix roll */
for (i = 0; i < t->total; i++, td++) {
if (td->extra) {
@@ -1065,6 +1070,8 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
* Setup internal data, mouse, vectors
*
* \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
*/
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
@@ -1121,6 +1128,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
zero_v3(t->vec);
zero_v3(t->center);
+ zero_v3(t->center_global);
unit_m3(t->mat);
@@ -1156,6 +1164,19 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->spacetype = sa->spacetype;
}
+ /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
+ if (op) {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
+ RNA_property_is_set(op->ptr, prop))
+ {
+ BKE_BIT_TEST_SET(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
+ }
+ }
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = sa->spacedata.first;
@@ -1316,7 +1337,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* use settings from scene only if modal */
if (t->flag & T_MODAL) {
if ((t->options & CTX_NO_PET) == 0) {
- if (t->obedit) {
+ if (t->spacetype == SPACE_IPO) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
+ }
+ else if (t->obedit) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
}
else if (t->options & CTX_GPENCIL_STROKES) {
@@ -1375,6 +1402,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
#endif
setTransformViewMatrices(t);
+ setTransformViewAspect(t, t->aspect);
initNumInput(&t->num);
}
@@ -1541,6 +1569,19 @@ void calculateCenter2D(TransInfo *t)
}
}
+void calculateCenterGlobal(TransInfo *t)
+{
+ /* setting constraint center */
+ /* note, init functions may over-ride t->center */
+ if (t->flag & (T_EDIT | T_POSE)) {
+ Object *ob = t->obedit ? t->obedit : t->poseobj;
+ mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ }
+ else {
+ copy_v3_v3(t->center_global, t->center);
+ }
+}
+
void calculateCenterCursor(TransInfo *t, float r_center[3])
{
const float *cursor;
@@ -1569,30 +1610,17 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
{
- float aspx = 1.0, aspy = 1.0;
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
- if (t->options & CTX_MASK) {
- ED_space_image_get_aspect(sima, &aspx, &aspy);
- }
- else {
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- }
cursor = sima->cursor;
}
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
- if (t->options & CTX_MOVIECLIP) {
- ED_space_clip_get_aspect_dimension_aware(space_clip, &aspx, &aspy);
- }
- else {
- ED_space_clip_get_aspect(space_clip, &aspx, &aspy);
- }
cursor = space_clip->cursor;
}
-
+
if (cursor) {
if (t->options & CTX_MASK) {
float co[2];
@@ -1609,8 +1637,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
BLI_assert(!"Shall not happen");
}
- r_center[0] = co[0] * aspx;
- r_center[1] = co[1] * aspy;
+ r_center[0] = co[0] * t->aspect[0];
+ r_center[1] = co[1] * t->aspect[1];
}
else if (t->options & CTX_PAINT_CURVE) {
if (t->spacetype == SPACE_IMAGE) {
@@ -1619,8 +1647,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
}
}
else {
- r_center[0] = cursor[0] * aspx;
- r_center[1] = cursor[1] * aspy;
+ r_center[0] = cursor[0] * t->aspect[0];
+ r_center[1] = cursor[1] * t->aspect[1];
}
}
}
@@ -1755,14 +1783,8 @@ void calculateCenter(TransInfo *t)
}
calculateCenter2D(t);
+ calculateCenterGlobal(t);
- /* setting constraint center */
- copy_v3_v3(t->con.center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->con.center);
- }
-
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
@@ -1783,7 +1805,7 @@ void calculateCenter(TransInfo *t)
/* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
if (t->mode == TFM_TRANSLATION) {
copy_v3_v3(t->center, axis);
- copy_v3_v3(t->con.center, t->center);
+ copy_v3_v3(t->center_global, t->center);
}
}
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index fc8e6cd0286..acc6108f264 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -512,7 +512,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(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
totsel++;
}
}
@@ -895,6 +895,11 @@ static void postOrtho(const bool ortho)
}
}
+BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
+{
+ return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
+}
+
static void draw_manipulator_rotate(
View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
const bool is_moving, const bool is_picksel)
@@ -908,8 +913,8 @@ static void draw_manipulator_rotate(
const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
bool ortho;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
/* Init stuff */
glDisable(GL_DEPTH_TEST);
@@ -1051,8 +1056,6 @@ static void draw_manipulator_rotate(
glRotatef(90.0, 1.0, 0.0, 0.0);
postOrtho(ortho);
}
-
- if (arcs) glDisable(GL_CLIP_PLANE0);
}
// donut arcs
if (arcs) {
@@ -1448,8 +1451,8 @@ static void draw_manipulator_rotate_cyl(
int axis_order[3] = {2, 0, 1};
int i;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
manipulator_axis_order(rv3d, axis_order);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index e33bc19fc92..013e47886eb 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -38,6 +38,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_editmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -63,23 +64,23 @@ typedef struct TransformModeItem {
static const float VecOne[3] = {1, 1, 1};
-static char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
-static char OP_ROTATION[] = "TRANSFORM_OT_rotate";
-static char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
-static char OP_RESIZE[] = "TRANSFORM_OT_resize";
-static char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
-static char OP_SHEAR[] = "TRANSFORM_OT_shear";
-static char OP_BEND[] = "TRANSFORM_OT_bend";
-static char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
-static char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
-static char OP_TILT[] = "TRANSFORM_OT_tilt";
-static char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
-static char OP_MIRROR[] = "TRANSFORM_OT_mirror";
-static char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
-static char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
-static char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
-static char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
-static char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
+static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
+static const char OP_ROTATION[] = "TRANSFORM_OT_rotate";
+static const char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
+static const char OP_RESIZE[] = "TRANSFORM_OT_resize";
+static const char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
+static const char OP_SHEAR[] = "TRANSFORM_OT_shear";
+static const char OP_BEND[] = "TRANSFORM_OT_bend";
+static const char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
+static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
+static const char OP_TILT[] = "TRANSFORM_OT_tilt";
+static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
+static const char OP_MIRROR[] = "TRANSFORM_OT_mirror";
+static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
+static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
+static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
+static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
@@ -140,6 +141,7 @@ EnumPropertyItem transform_mode_types[] =
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bonesize", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone_Envelope", ""},
+ {TFM_BONE_ENVELOPE_DIST, "BONE_ENVELOPE_DIST", 0, "Bone_Envelope_Distance", ""},
{TFM_CURVE_SHRINKFATTEN, "CURVE_SHRINKFATTEN", 0, "Curve_Shrinkfatten", ""},
{TFM_MASK_SHRINKFATTEN, "MASK_SHRINKFATTEN", 0, "Mask_Shrinkfatten", ""},
{TFM_GPENCIL_SHRINKFATTEN, "GPENCIL_SHRINKFATTEN", 0, "GPencil_Shrinkfatten", ""},
@@ -488,7 +490,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* add temp handler */
WM_event_add_modal_handler(C, op);
- op->flag |= OP_GRAB_POINTER; // XXX maybe we want this with the manipulator only?
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the manipulator only?
return OPERATOR_RUNNING_MODAL;
}
}
@@ -790,6 +792,8 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -834,6 +838,8 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Edge Slide";
ot->description = "Slide an edge loop along a mesh";
@@ -845,9 +851,12 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
- RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+ RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
+
+ prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
@@ -865,7 +874,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
@@ -1118,7 +1127,7 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element");
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_node_element");
break;
case SPACE_SEQ:
WM_keymap_add_item(keymap, OP_SEQ_SLIDE, GKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 4a2927ace00..1b0256bdeed 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -454,7 +454,7 @@ void applySnapping(TransInfo *t, float *vec)
t->tsnap.applySnap(t, vec);
}
- else if ((t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) && activeSnap(t)) {
+ else if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t)) {
double current = PIL_check_seconds_timer();
// Time base quirky code to go around findnearest slowness
@@ -577,6 +577,10 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ /* We do our own snapping currently, so nothing here */
+ t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
+ }
else {
/* Always grid outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
@@ -837,16 +841,10 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f
static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
{
- float angle, start[3], end[3], center[3];
-
- copy_v3_v3(center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, center);
- }
+ float angle, start[3], end[3];
- sub_v3_v3v3(start, p1, center);
- sub_v3_v3v3(end, p2, center);
+ sub_v3_v3v3(start, p1, t->center_global);
+ sub_v3_v3v3(end, p2, t->center_global);
// Angle around a constraint axis (error prone, will need debug)
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
@@ -893,16 +891,10 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3])
{
- float d1[3], d2[3], center[3], len_d1;
-
- copy_v3_v3(center, t->center);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, center);
- }
+ float d1[3], d2[3], len_d1;
- sub_v3_v3v3(d1, p1, center);
- sub_v3_v3v3(d2, p2, center);
+ sub_v3_v3v3(d1, p1, t->center_global);
+ sub_v3_v3v3(d2, p2, t->center_global);
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
mul_m3_v3(t->con.pmtx, d1);
@@ -949,9 +941,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
// last_p = LAST_SNAP_POINT;
// }
// else
-// {
+ {
last_p = t->tsnap.snapPoint;
-// }
+ }
for (p1 = depth_peels.first; p1; p1 = p1->next) {
@@ -1041,14 +1033,13 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
/* same as above but for UV's */
Image *ima = ED_space_image(t->sa->spacedata.first);
- float aspx, aspy, co[2];
+ float co[2];
UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
- t->tsnap.snapPoint[0] *= aspx;
- t->tsnap.snapPoint[1] *= aspy;
+ t->tsnap.snapPoint[0] *= t->aspect[0];
+ t->tsnap.snapPoint[1] *= t->aspect[1];
t->tsnap.status |= POINT_INIT;
}
@@ -1109,13 +1100,7 @@ static void TargetSnapCenter(TransInfo *t)
{
/* Only need to calculate once */
if ((t->tsnap.status & TARGET_INIT) == 0) {
- copy_v3_v3(t->tsnap.snapTarget, t->center);
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
- }
-
+ copy_v3_v3(t->tsnap.snapTarget, t->center_global);
TargetSnapOffset(t, NULL);
t->tsnap.status |= TARGET_INIT;
@@ -1396,11 +1381,8 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
if (arm->edbo) {
EditBone *eBone;
@@ -1758,11 +1740,8 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
switch (snap_mode) {
case SCE_SNAP_MODE_VERTEX:
@@ -2107,12 +2086,8 @@ static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
/* If number of vert is more than an arbitrary limit,
* test against boundbox first
@@ -2418,8 +2393,8 @@ void snapGridIncrement(TransInfo *t, float *val)
{
GearsType action;
- // Only do something if using Snap to Grid
- if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT)
+ /* only do something if using absolute or incremental grid snapping */
+ if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))
return;
action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
@@ -2431,7 +2406,7 @@ void snapGridIncrement(TransInfo *t, float *val)
snapGridIncrementAction(t, val, action);
}
-int snapSequenceBounds(TransInfo *t, const int mval[2])
+void snapSequenceBounds(TransInfo *t, const int mval[2])
{
float xmouse, ymouse;
int frame;
@@ -2439,7 +2414,7 @@ int snapSequenceBounds(TransInfo *t, const int mval[2])
TransSeq *ts = t->customData;
/* reuse increment, strictly speaking could be another snap mode, but leave as is */
if (!(t->modifiers & MOD_SNAP_INVERT))
- return 0;
+ return;
/* convert to frame range */
UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
@@ -2450,50 +2425,58 @@ int snapSequenceBounds(TransInfo *t, const int mval[2])
if (!ts->snap_left)
frame = frame - (ts->max - ts->min);
- return frame;
+ t->values[0] = frame - ts->min;
}
static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
{
+ float asp_local[3] = {1, 1, 1};
+ const bool use_aspect = ELEM(t->mode, TFM_TRANSLATION);
+ const float *asp = use_aspect ? t->aspect : asp_local;
int i;
- float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
- if (max_index > 2) {
- printf("applyGridIncrement: invalid index %d, clamping\n", max_index);
- max_index = 2;
- }
+ BLI_assert(ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID));
+ BLI_assert(max_index <= 2);
- // Early bailing out if no need to snap
- if (fac[action] == 0.0f)
+ /* Early bailing out if no need to snap */
+ if (fac[action] == 0.0f) {
return;
-
- /* evil hack - snapping needs to be adapted for image aspect ratio */
- if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
- if (t->options & CTX_MASK) {
- ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1);
- }
- else if (t->options & CTX_PAINT_CURVE) {
- asp[0] = asp[1] = 1.0;
- }
- else {
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1);
- }
}
- else if ((t->spacetype == SPACE_IPO) && (t->mode == TFM_TRANSLATION)) {
- View2D *v2d = &t->ar->v2d;
- View2DGrid *grid;
- SpaceIpo *sipo = t->sa->spacedata.first;
- int unity = V2D_UNIT_VALUES;
- int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
- /* grid */
- grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy);
+ if (use_aspect) {
+ /* custom aspect for fcurve */
+ if (t->spacetype == SPACE_IPO) {
+ View2D *v2d = &t->ar->v2d;
+ View2DGrid *grid;
+ SpaceIpo *sipo = t->sa->spacedata.first;
+ int unity = V2D_UNIT_VALUES;
+ int unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
+
+ /* grid */
+ grid = UI_view2d_grid_calc(t->scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, t->ar->winx, t->ar->winy);
+
+ UI_view2d_grid_size(grid, &asp_local[0], &asp_local[1]);
+ UI_view2d_grid_free(grid);
- UI_view2d_grid_size(grid, &asp[0], &asp[1]);
- UI_view2d_grid_free(grid);
+ asp = asp_local;
+ }
}
- for (i = 0; i <= max_index; i++) {
- val[i] = fac[action] * asp[i] * floorf(val[i] / (fac[action] * asp[i]) + 0.5f);
+ /* absolute snapping on grid based on global center */
+ if ((t->tsnap.mode == SCE_SNAP_MODE_GRID) && (t->mode == TFM_TRANSLATION)) {
+ for (i = 0; i <= max_index; i++) {
+ /* do not let unconstrained axis jump to absolute grid increments */
+ if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
+ const float iter_fac = fac[action] * asp[i];
+ val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ }
+ }
+ }
+ else {
+ /* relative snapping in fixed increments */
+ for (i = 0; i <= max_index; i++) {
+ const float iter_fac = fac[action] * asp[i];
+ val[i] = iter_fac * roundf(val[i] / iter_fac);
+ }
}
}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index f4189a18da4..47894e1bc1f 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../imbuf
../../gpu
../../makesdna
../../makesrna
@@ -69,6 +70,7 @@ set(SRC
../include/ED_node.h
../include/ED_numinput.h
../include/ED_object.h
+ ../include/ED_outliner.h
../include/ED_paint.h
../include/ED_particle.h
../include/ED_physics.h
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 438eb1f3864..433c7603f35 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_packedFile_types.h"
@@ -58,9 +59,12 @@
#include "BKE_paint.h"
#include "ED_armature.h"
+#include "ED_buttons.h"
#include "ED_image.h"
#include "ED_mesh.h"
+#include "ED_node.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_paint.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -318,3 +322,25 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
glEnd();
setlinestyle(0);
}
+
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \note Typically notifiers take care of this,
+ * but there are times we have to free references immediately, see: T44376
+ */
+void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+{
+
+ switch (sl->spacetype) {
+ case SPACE_OUTLINER:
+ ED_outliner_id_unref((SpaceOops *)sl, id);
+ break;
+ case SPACE_BUTS:
+ ED_buttons_id_unref((SpaceButs *)sl, id);
+ break;
+ case SPACE_NODE:
+ ED_node_id_unref((SpaceNode *)sl, id);
+ break;
+ }
+}
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 7f5edb5ea9e..bc7a8374c73 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -315,7 +315,7 @@ void undo_editmode_name(bContext *C, const char *undoname)
}
/* undoname optionally, if NULL it just checks for existing undo steps */
-int undo_editmode_valid(const char *undoname)
+bool undo_editmode_is_valid(const char *undoname)
{
if (undoname) {
UndoElem *uel;
@@ -332,19 +332,20 @@ int undo_editmode_valid(const char *undoname)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *undo_editmode_get_name(bContext *C, int nr, int *active)
+const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
{
UndoElem *uel;
/* prevent wrong numbers to be returned */
undo_clean_stack(C);
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&undobase, nr);
if (uel) {
- if (active && uel == curundo)
- *active = 1;
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 050631362b4..effb45a61ab 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -73,14 +73,14 @@ void initNumInput(NumInput *n)
{
n->idx_max = 0;
n->unit_sys = USER_UNIT_NONE;
- fill_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
+ copy_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
n->unit_use_radians = false;
n->flag = 0;
- fill_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
+ copy_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
zero_v3(n->val);
- fill_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
- fill_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
+ copy_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
+ copy_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
n->idx = 0;
n->str[0] = '\0';
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index ab882a388ad..ee6101d2952 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -108,7 +108,7 @@ void ED_undo_push(bContext *C, const char *str)
/* do nothing for now */
}
else {
- BKE_write_undo(C, str);
+ BKE_undo_write(C, str);
}
if (wm->file_saved) {
@@ -244,7 +244,7 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
}
/* name optionally, function used to check for operator redo panel */
-int ED_undo_valid(const bContext *C, const char *undoname)
+bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -263,7 +263,7 @@ int ED_undo_valid(const bContext *C, const char *undoname)
}
else if (obedit) {
if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- return undo_editmode_valid(undoname);
+ return undo_editmode_is_valid(undoname);
}
}
else {
@@ -271,19 +271,19 @@ int ED_undo_valid(const bContext *C, const char *undoname)
/* if below tests fail, global undo gets executed */
if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
- if (ED_undo_paint_valid(UNDO_PAINT_IMAGE, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
- if (ED_undo_paint_valid(UNDO_PAINT_MESH, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_valid(CTX_data_scene(C));
+ return PE_undo_is_valid(CTX_data_scene(C));
}
if (U.uiflag & USER_GLOBALUNDO) {
- return BKE_undo_valid(undoname);
+ return BKE_undo_is_valid(undoname);
}
}
return 0;
@@ -487,7 +487,8 @@ static int get_undo_system(bContext *C)
static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
- int active, i = 0;
+ int i = 0;
+ bool active;
while (true) {
const char *name = NULL;
diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/util/util_intern.h
index d366ad7997f..0f650330951 100644
--- a/source/blender/editors/util/util_intern.h
+++ b/source/blender/editors/util/util_intern.h
@@ -35,12 +35,12 @@
/* internal exports only */
/* editmode_undo.c */
-void undo_editmode_name (struct bContext *C, const char *undoname);
-int undo_editmode_valid (const char *undoname);
-const char *undo_editmode_get_name (struct bContext *C, int nr, int *active);
-void *undo_editmode_get_prev (struct Object *ob);
-void undo_editmode_step (struct bContext *C, int step);
-void undo_editmode_number (struct bContext *C, int nr);
+void undo_editmode_name(struct bContext *C, const char *undoname);
+bool undo_editmode_is_valid(const char *undoname);
+const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active);
+void *undo_editmode_get_prev(struct Object *ob);
+void undo_editmode_step(struct bContext *C, int step);
+void undo_editmode_number(struct bContext *C, int nr);
#endif /* __UTIL_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index d1fd8d969a4..e028c08091c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -34,18 +34,13 @@
struct MTexPoly;
struct Image;
-struct MTFace;
struct Object;
struct Scene;
struct SpaceImage;
-struct UvElementMap;
struct wmOperatorType;
struct BMEditMesh;
-struct BMesh;
struct BMFace;
struct BMLoop;
-struct BMEdge;
-struct BMVert;
/* visibility and selection */
bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index c70fcdbbd94..3b40dad3f3b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -53,6 +53,8 @@
#include "BLI_blenlib.h"
#include "BLI_array.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
@@ -80,6 +82,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "uvedit_intern.h"
@@ -1028,7 +1032,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/* setup */
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
@@ -1114,7 +1118,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/*********************** linked select ***********************/
-static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend)
+static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces)
{
BMFace *efa;
BMLoop *l;
@@ -1131,7 +1135,9 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- vmap = BM_uv_vert_map_create(em->bm, 1, limit);
+
+ /* 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);
if (vmap == NULL)
return;
@@ -1144,15 +1150,24 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
stacksize++;
flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- break;
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
}
}
}
@@ -1204,13 +1219,21 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!extend) {
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
+ if (select_faces) {
if (flag[a])
- luv->flag |= MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, true);
else
- luv->flag &= ~MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (flag[a])
+ luv->flag |= MLOOPUV_VERTSEL;
+ else
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1219,17 +1242,23 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!flag[a]) {
continue;
}
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
break;
- }
}
-
- if (l) {
- break;
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ break;
+ }
+ }
+
+ if (l) {
+ break;
+ }
}
}
@@ -1239,10 +1268,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag &= ~MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1252,10 +1286,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag |= MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, true);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -2087,7 +2126,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 1 vertex as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hituv[hit.lindex] = hit.luv->uv;
@@ -2104,7 +2143,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 2 edge vertices as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
@@ -2154,7 +2193,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
flush = uv_select_edgeloop(scene, ima, em, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
- uv_select_linked(scene, ima, em, limit, &hit, extend);
+ uv_select_linked(scene, ima, em, limit, &hit, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2375,11 +2414,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
NearestHit hit, *hit_p = NULL;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled");
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
return OPERATOR_CANCELLED;
}
@@ -2405,7 +2445,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
hit_p = &hit;
}
- uv_select_linked(scene, ima, em, limit, hit_p, extend);
+ uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -2680,7 +2720,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -2771,7 +2811,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -3064,9 +3104,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE);
+ const bool use_face_center = (
+ (ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -4002,7 +4043,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
/* This code sets editvert->tmp.l to the index. This will be useful later on. */
BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, 0, limit);
+ vmap = BM_uv_vert_map_create(bm, limit, false, false);
BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
/* flags to determine if we uv is separated from first editface match */
@@ -4107,7 +4148,7 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
}
-static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
+static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
@@ -4117,13 +4158,17 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
BMFace *efa;
BMLoop *loop;
BMIter iter, liter;
+ bool clear = RNA_boolean_get(op->ptr, "clear");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
+ if (clear)
+ BM_elem_flag_disable(loop->e, BM_ELEM_SEAM);
+ else
+ BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
}
}
}
@@ -4139,10 +4184,27 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), ICON_NONE, op->type->idname, "clear", false);
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), ICON_NONE, op->type->idname, "clear", true);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
static void UV_OT_mark_seam(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Mark Seams";
+ ot->name = "Mark Seam";
ot->description = "Mark selected UV edges as seams";
ot->idname = "UV_OT_mark_seam";
@@ -4151,7 +4213,10 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_mark_seam_exec;
+ ot->invoke = uv_mark_seam_invoke;
ot->poll = ED_operator_uvedit;
+
+ RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
}
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index f7a8735ccca..828537fd585 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1649,10 +1649,10 @@ static int stitch_init(bContext *C, wmOperator *op)
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, false, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
}
else {
- state->element_map = BM_uv_element_map_create(state->em->bm, true, true);
+ state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
}
if (!state->element_map) {
state_delete(state);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 793f84b05ec..f915a4b2e51 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -681,7 +681,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* identifiers */
ot->name = "Minimize Stretch";
ot->idname = "UV_OT_minimize_stretch";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
ot->description = "Reduce UV stretching by relaxing angles";
/* api callbacks */
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index 9766372507b..975b1212695 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -45,9 +45,10 @@ void FRS_initialize(void);
void FRS_set_context(struct bContext *C);
void FRS_read_file(struct bContext *C);
int FRS_is_freestyle_enabled(struct SceneRenderLayer *srl);
-void FRS_init_stroke_rendering(struct Render *re);
+void FRS_init_stroke_renderer(struct Render *re);
+void FRS_begin_stroke_rendering(struct Render *re);
struct Render *FRS_do_stroke_rendering(struct Render *re, struct SceneRenderLayer *srl, int render);
-void FRS_finish_stroke_rendering(struct Render *re);
+void FRS_end_stroke_rendering(struct Render *re);
void FRS_free_view_map_cache(void);
void FRS_composite_result(struct Render *re, struct SceneRenderLayer *srl, struct Render *freestyle_render);
void FRS_exit(void);
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index ae202412c09..9de426b91ab 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -58,7 +58,7 @@ extern "C" {
namespace Freestyle {
-AppView::AppView(const char *iName)
+AppView::AppView(const char * /*iName*/)
{
_Fovy = DEG2RADF(30.0f);
_ModelRootNode = new NodeDrawingStyle;
diff --git a/source/blender/freestyle/intern/application/AppView.h b/source/blender/freestyle/intern/application/AppView.h
index 14101909ca1..6338ace53c0 100644
--- a/source/blender/freestyle/intern/application/AppView.h
+++ b/source/blender/freestyle/intern/application/AppView.h
@@ -100,12 +100,12 @@ public:
_SilhouetteRootNode->AddChild(iSilhouette);
}
- inline void Add2DSilhouette(NodeGroup *iSilhouette)
+ inline void Add2DSilhouette(NodeGroup * /*iSilhouette*/)
{
//_pFENode->AddChild(iSilhouette);
}
- inline void Add2DVisibleSilhouette(NodeGroup *iVSilhouette)
+ inline void Add2DVisibleSilhouette(NodeGroup * /*iVSilhouette*/)
{
//_pVisibleSilhouetteNode->AddChild(iVSilhouette);
}
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 8d9b1a4fb52..5cd2e16847d 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -927,13 +927,19 @@ void Controller::InsertStyleModule(unsigned index, const char *iFileName)
_Canvas->InsertStyleModule(index, sm);
}
+void Controller::InsertStyleModule(unsigned index, const char *iName, const char *iBuffer)
+{
+ StyleModule *sm = new BufferedStyleModule(iBuffer, iName, _inter);
+ _Canvas->InsertStyleModule(index, sm);
+}
+
void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText)
{
StyleModule *sm = new BlenderStyleModule(iText, iName, _inter);
_Canvas->InsertStyleModule(index, sm);
}
-void Controller::AddStyleModule(const char *iFileName)
+void Controller::AddStyleModule(const char * /*iFileName*/)
{
//_pStyleWindow->Add(iFileName);
}
@@ -1003,7 +1009,7 @@ void Controller::toggleEdgeTesselationNature(Nature::EdgeNature iNature)
ComputeViewMap();
}
-void Controller::setModelsDir(const string& dir)
+void Controller::setModelsDir(const string& /*dir*/)
{
//_current_dirs->setValue("models/dir", dir);
}
@@ -1015,7 +1021,7 @@ string Controller::getModelsDir() const
return dir;
}
-void Controller::setModulesDir(const string& dir)
+void Controller::setModulesDir(const string& /*dir*/)
{
//_current_dirs->setValue("modules/dir", dir);
}
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 9fe57d92cf4..a09964a4e79 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -90,6 +90,7 @@ public:
Render *RenderStrokes(Render *re, bool render);
void SwapStyleModules(unsigned i1, unsigned i2);
void InsertStyleModule(unsigned index, const char *iFileName);
+ void InsertStyleModule(unsigned index, const char *iName, const char *iBuffer);
void InsertStyleModule(unsigned index, const char *iName, struct Text *iText);
void AddStyleModule(const char *iFileName);
void RemoveStyleModule(unsigned index);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index dfcc77d3b23..7a61b735c4d 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -64,12 +64,11 @@ NodeGroup *BlenderFileLoader::Load()
_viewplane_bottom = _re->viewplane.ymin;
_viewplane_top = _re->viewplane.ymax;
- if ((_re->r.scemode & R_VIEWPORT_PREVIEW) && (_re->r.mode & R_ORTHO)) {
+ if (_re->clipsta < 0.f) {
// Adjust clipping start/end and set up a Z offset when the viewport preview
// is used with the orthographic view. In this case, _re->clipsta is negative,
// while Freestyle assumes that imported mesh data are in the camera coordinate
// system with the view point located at origin [bug #36009].
- BLI_assert(_re->clipsta < 0.f);
_z_near = -0.001f;
_z_offset = _re->clipsta + _z_near;
_z_far = -_re->clipend + _z_offset;
@@ -256,6 +255,7 @@ void BlenderFileLoader::clipTriangle(int numTris, float triCoords[][3], float v1
}
}
BLI_assert(k == 2 + numTris);
+ (void)numTris; /* Ignored in release builds. */
}
void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
@@ -536,8 +536,12 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
else {
RE_vlakren_get_normal(_re, obi, vlr, facenormal);
#ifndef NDEBUG
+ /* test if normals are inverted in rendering [T39669] */
float tnor[3];
- normal_tri_v3(tnor, v3, v2, v1); /* normals are inverted in rendering */
+ if (vlr->v4)
+ normal_quad_v3(tnor, v4, v3, v2, v1);
+ else
+ normal_tri_v3(tnor, v3, v2, v1);
BLI_assert(dot_v3v3(tnor, facenormal) > 0.0f);
#endif
copy_v3_v3(n1, facenormal);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index f304e8ae9bd..64ef49d74a3 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -94,7 +94,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
//freestyle_scene->r.maximsize = old_scene->r.maximsize; /* DEPRECATED */
freestyle_scene->r.ocres = old_scene->r.ocres;
freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
- freestyle_scene->r.scemode = old_scene->r.scemode & ~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE);
+ freestyle_scene->r.scemode = old_scene->r.scemode & ~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE | R_MULTIVIEW);
freestyle_scene->r.flag = old_scene->r.flag;
freestyle_scene->r.threads = old_scene->r.threads;
freestyle_scene->r.border.xmin = old_scene->r.border.xmin;
@@ -126,7 +126,8 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
BKE_scene_set_background(freestyle_bmain, freestyle_scene);
// Camera
- Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA);
+ Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA, NULL);
+ DAG_relations_tag_update(freestyle_bmain);
Camera *camera = (Camera *)object_camera->data;
camera->type = CAM_ORTHO;
@@ -506,6 +507,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// If still no material, create one
if (!has_mat) {
Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
+ DAG_relations_tag_update(freestyle_bmain);
ma->mode |= MA_VERTEXCOLP;
ma->mode |= MA_TRANSP;
ma->mode |= MA_SHLESS;
@@ -668,6 +670,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
{
#if 0
Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH);
+ DAG_relations_tag_update(freestyle_bmain);
#else
Object *object_mesh = NewMesh();
#endif
@@ -938,6 +941,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
ob->lay = 1;
base = BKE_scene_base_add(freestyle_scene, ob);
+ DAG_relations_tag_update(freestyle_bmain);
#if 0
BKE_scene_base_deselect_all(scene);
BKE_scene_base_select(scene, base);
@@ -950,7 +954,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
return ob;
}
-Render *BlenderStrokeRenderer::RenderScene(Render *re, bool render)
+Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
{
Camera *camera = (Camera *)freestyle_scene->camera->data;
if (camera->clipend < _z)
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
index 21776396ebc..1d73125f627 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
@@ -31,12 +31,39 @@
extern "C" {
#include "BLI_utildefines.h" // BLI_assert()
-struct Scene;
struct Text;
}
namespace Freestyle {
+class BufferedStyleModule : public StyleModule
+{
+public:
+ BufferedStyleModule(const string& buffer, const string& file_name, Interpreter *inter) : StyleModule(file_name, inter)
+ {
+ _buffer = buffer;
+ }
+
+ virtual ~BufferedStyleModule()
+ {
+ }
+
+protected:
+ virtual int interpret()
+ {
+ PythonInterpreter *py_inter = dynamic_cast<PythonInterpreter*>(_inter);
+ BLI_assert(py_inter != 0);
+ return py_inter->interpretString(_buffer, getFileName());
+ }
+
+private:
+ string _buffer;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BufferedStyleModule")
+#endif
+};
+
class BlenderStyleModule : public StyleModule
{
public:
@@ -63,7 +90,6 @@ private:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStyleModule")
#endif
-
};
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 32b4c5455a7..46724ff530a 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -87,7 +87,7 @@ int freestyle_viewport[4];
// current scene
Scene *freestyle_scene;
-static void load_post_callback(struct Main *main, struct ID *id, void *arg)
+static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
{
lineset_copied = false;
}
@@ -211,16 +211,12 @@ static char *escape_quotes(char *name)
return s;
}
-static Text *create_lineset_handler(Main *bmain, char *layer_name, char *lineset_name)
+static char * create_lineset_handler(char *layer_name, char *lineset_name)
{
+ const char *fmt = "__import__('parameter_editor').process('%s', '%s')\n";
char *s1 = escape_quotes(layer_name);
char *s2 = escape_quotes(lineset_name);
- Text *text = BKE_text_add(bmain, lineset_name);
- BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
- BKE_text_write(text, s1);
- BKE_text_write(text, "', '");
- BKE_text_write(text, s2);
- BKE_text_write(text, "')\n");
+ char *text = BLI_sprintfN(fmt, s1, s2);
MEM_freeN(s1);
MEM_freeN(s2);
return text;
@@ -293,7 +289,7 @@ static bool test_edge_type_conditions(struct edge_type_condition *conditions,
return true;
}
-static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
+static void prepare(Render *re, SceneRenderLayer *srl)
{
// load mesh
re->i.infostr = "Freestyle: Mesh loading";
@@ -369,9 +365,10 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
cout << " " << layer_count+1 << ": " << lineset->name << " - " <<
(lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
}
- Text *text = create_lineset_handler(bmain, srl->name, lineset->name);
- controller->InsertStyleModule(layer_count, lineset->name, text);
+ char *buffer = create_lineset_handler(srl->name, lineset->name);
+ controller->InsertStyleModule(layer_count, lineset->name, buffer);
controller->toggleLayer(layer_count, true);
+ MEM_freeN(buffer);
if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
++use_ridges_and_valleys;
++use_suggestive_contours;
@@ -494,13 +491,20 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
return;
rl = render_get_active_layer( freestyle_render, freestyle_render->result );
- if (!rl || rl->rectf == NULL) {
+ if (!rl) {
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "No Freestyle result image to composite" << endl;
+ cout << "No source render layer to composite" << endl;
+ }
+ return;
+ }
+
+ src = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, freestyle_render->viewname);
+ if (!src) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "No source result image to composite" << endl;
}
return;
}
- src = rl->rectf;
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "src: " << rl->rectx << " x " << rl->recty << endl;
@@ -508,13 +512,19 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
#endif
rl = RE_GetRenderLayer(re->result, srl->name);
- if (!rl || rl->rectf == NULL) {
+ if (!rl) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "No destination render layer to composite to" << endl;
+ }
+ return;
+ }
+ dest = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ if (!dest) {
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "No layer to composite to" << endl;
+ cout << "No destination result image to composite to" << endl;
}
return;
}
- dest = rl->rectf;
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
@@ -566,7 +576,7 @@ int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
}
-void FRS_init_stroke_rendering(Render *re)
+void FRS_init_stroke_renderer(Render *re)
{
if (G.debug & G_DEBUG_FREESTYLE) {
cout << endl;
@@ -576,16 +586,18 @@ void FRS_init_stroke_rendering(Render *re)
}
init_view(re);
- init_camera(re);
controller->ResetRenderCount();
}
+void FRS_begin_stroke_rendering(Render *re)
+{
+ init_camera(re);
+}
+
Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
{
- Main *freestyle_bmain = re->freestyle_bmain;
Render *freestyle_render = NULL;
- Text *text, *next_text;
if (!render)
return controller->RenderStrokes(re, false);
@@ -606,7 +618,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// - add style modules
// - set parameters
// - compute view map
- prepare(freestyle_bmain, re, srl);
+ prepare(re, srl);
if (re->test_break(re->tbh)) {
controller->CloseFile();
@@ -634,18 +646,10 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
}
}
- // Free temp main (currently only text blocks are stored there)
- for (text = (Text *)freestyle_bmain->text.first; text; text = next_text) {
- next_text = (Text *) text->id.next;
-
- BKE_text_unlink(freestyle_bmain, text);
- BKE_libblock_free(freestyle_bmain, text);
- }
-
return freestyle_render;
}
-void FRS_finish_stroke_rendering(Render *re)
+void FRS_end_stroke_rendering(Render * /*re*/)
{
// clear canvas
controller->Clear();
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
index a750cf2f7cf..3eb92c559fe 100644
--- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -495,7 +495,7 @@ bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin an
real t0, real t1,
real& tmin, // I0 = orig + tmin * dir is the first intersection
real& tmax, // I1 = orig + tmax * dir is the second intersection
- real epsilon)
+ real /*epsilon*/)
{
float tymin, tymax, tzmin, tzmax;
Vec3r inv_direction(1.0 / dir[0], 1.0 / dir[1], 1.0 / dir[2]);
diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h
index c1d04f6b4cc..62c0e58232a 100644
--- a/source/blender/freestyle/intern/geometry/Grid.h
+++ b/source/blender/freestyle/intern/geometry/Grid.h
@@ -97,11 +97,11 @@ class GridVisitor
public:
virtual ~GridVisitor() {}; //soc
- virtual void discoverCell(Cell *cell) {}
+ virtual void discoverCell(Cell * /*cell*/) {}
- virtual void examineOccluder(Polygon3r *occ) {}
+ virtual void examineOccluder(Polygon3r * /*occ*/) {}
- virtual void finishCell(Cell *cell) {}
+ virtual void finishCell(Cell * /*cell*/) {}
virtual bool stop() {
return false;
diff --git a/source/blender/freestyle/intern/image/Image.h b/source/blender/freestyle/intern/image/Image.h
index 577dc0fb866..2e78e784214 100644
--- a/source/blender/freestyle/intern/image/Image.h
+++ b/source/blender/freestyle/intern/image/Image.h
@@ -134,7 +134,7 @@ public:
return _height;
}
- /*! Returns the grey value for pixel x,y */
+ /*! Returns the gray value for pixel x,y */
virtual float pixel(unsigned x, unsigned y) const = 0;
/*! Sets the array.
diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp
index 251f47bc44c..b81f8303945 100644
--- a/source/blender/freestyle/intern/image/ImagePyramid.cpp
+++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp
@@ -42,7 +42,7 @@ ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels)
}
#endif
-ImagePyramid::ImagePyramid(const ImagePyramid& iBrother)
+ImagePyramid::ImagePyramid(const ImagePyramid& /*iBrother*/)
{
if (!_levels.empty()) {
for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
index ad54a81f156..50d82656819 100644
--- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
@@ -46,7 +46,7 @@ static char ContextFunctions_get_time_stamp___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_time_stamp(PyObject *self)
+ContextFunctions_get_time_stamp(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetTimeStampCF());
}
@@ -60,7 +60,7 @@ static char ContextFunctions_get_canvas_width___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_canvas_width(PyObject *self)
+ContextFunctions_get_canvas_width(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetCanvasWidthCF());
}
@@ -74,7 +74,7 @@ static char ContextFunctions_get_canvas_height___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_canvas_height(PyObject *self)
+ContextFunctions_get_canvas_height(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetCanvasHeightCF());
}
@@ -88,7 +88,7 @@ static char ContextFunctions_get_border___doc__[] =
" :rtype: tuple\n";
static PyObject *
-ContextFunctions_get_border(PyObject *self)
+ContextFunctions_get_border(PyObject * /*self*/)
{
BBox<Vec2i> border(ContextFunctions::GetBorderCF());
PyObject *v = PyTuple_New(4);
@@ -117,7 +117,7 @@ static char ContextFunctions_load_map___doc__[] =
" :type sigma: float\n";
static PyObject *
-ContextFunctions_load_map(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_load_map(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"file_name", "map_name", "num_levels", "sigma", NULL};
char *fileName, *mapName;
@@ -150,7 +150,7 @@ static char ContextFunctions_read_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"map_name", "level", "x", "y", NULL};
char *mapName;
@@ -180,7 +180,7 @@ static char ContextFunctions_read_complete_view_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_complete_view_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_complete_view_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"level", "x", "y", NULL};
int level;
@@ -212,7 +212,7 @@ static char ContextFunctions_read_directional_view_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_directional_view_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_directional_view_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"orientation", "level", "x", "y", NULL};
int orientation, level;
@@ -232,7 +232,7 @@ static char ContextFunctions_get_selected_fedge___doc__[] =
" :rtype: :class:`FEdge`\n";
static PyObject *
-ContextFunctions_get_selected_fedge(PyObject *self)
+ContextFunctions_get_selected_fedge(PyObject * /*self*/)
{
FEdge *fe = ContextFunctions::GetSelectedFEdgeCF();
if (fe)
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 487a473b7bd..d22632040f4 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -72,7 +72,7 @@ static char Freestyle_getCurrentScene___doc__[] =
" :return: The current scene.\n"
" :rtype: :class:`bpy.types.Scene`\n";
-static PyObject *Freestyle_getCurrentScene(PyObject *self)
+static PyObject *Freestyle_getCurrentScene(PyObject * /*self*/)
{
if (!freestyle_scene) {
PyErr_SetString(PyExc_TypeError, "current scene not available");
@@ -126,7 +126,7 @@ static char Freestyle_blendRamp___doc__[] =
" :return: Blended color in RGB format.\n"
" :rtype: :class:`mathutils.Vector`\n";
-static PyObject *Freestyle_blendRamp(PyObject *self, PyObject *args)
+static PyObject *Freestyle_blendRamp(PyObject * /*self*/, PyObject *args)
{
PyObject *obj1, *obj2;
char *s;
@@ -170,7 +170,7 @@ static char Freestyle_evaluateColorRamp___doc__[] =
" :return: color in RGBA format.\n"
" :rtype: :class:`mathutils.Vector`\n";
-static PyObject *Freestyle_evaluateColorRamp(PyObject *self, PyObject *args)
+static PyObject *Freestyle_evaluateColorRamp(PyObject * /*self*/, PyObject *args)
{
BPy_StructRNA *py_srna;
ColorBand *coba;
@@ -207,7 +207,7 @@ static char Freestyle_evaluateCurveMappingF___doc__[] =
" :return: Mapped output value.\n"
" :rtype: float\n";
-static PyObject *Freestyle_evaluateCurveMappingF(PyObject *self, PyObject *args)
+static PyObject *Freestyle_evaluateCurveMappingF(PyObject * /*self*/, PyObject *args)
{
BPy_StructRNA *py_srna;
CurveMapping *cumap;
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
index 4d0d140474a..a36d446fcb7 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -30,6 +30,9 @@
extern "C" {
#endif
+#include "BLI_hash_mm2a.h"
+
+
///////////////////////////////////////////////////////////////////////////////////////////
//-------------------MODULE INITIALIZATION--------------------------------
@@ -478,6 +481,48 @@ static PyGetSetDef BPy_FrsMaterial_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
+static PyObject *BPy_FrsMaterial_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ const BPy_FrsMaterial *matA = NULL, *matB = NULL;
+ bool result = 0;
+
+ if (!BPy_FrsMaterial_Check(objectA) || !BPy_FrsMaterial_Check(objectB)) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+ }
+
+ matA = (BPy_FrsMaterial *)objectA;
+ matB = (BPy_FrsMaterial *)objectB;
+
+ switch (comparison_type) {
+ case Py_NE:
+ result = (*matA->m) != (*matB->m);
+ break;
+ case Py_EQ:
+ result = (*matA->m) == (*matB->m);
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "Material does not support this comparison type");
+ return NULL;
+ }
+
+ if (result == true) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+}
+
+
+static Py_hash_t FrsMaterial_hash(PyObject *self)
+{
+ return (Py_uhash_t)BLI_hash_mm2((const unsigned char *)self, sizeof(*self), 0);
+}
/*-----------------------BPy_FrsMaterial type definition ------------------------------*/
PyTypeObject FrsMaterial_Type = {
@@ -494,7 +539,7 @@ PyTypeObject FrsMaterial_Type = {
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- 0, /* tp_hash */
+ (hashfunc)FrsMaterial_hash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
@@ -504,7 +549,7 @@ PyTypeObject FrsMaterial_Type = {
FrsMaterial_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ (richcmpfunc)BPy_FrsMaterial_richcmpr, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
index 7a3624f248e..0db25753caa 100644
--- a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
+++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
@@ -63,7 +63,7 @@ PyDoc_STRVAR(Integrator_integrate_doc,
" :class:`UnaryFunction0DUnsigned` type.\n"
" :rtype: int or float");
-static PyObject * Integrator_integrate(PyObject *self, PyObject *args, PyObject *kwds)
+static PyObject * Integrator_integrate(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"func", "it", "it_end", "integration_type", NULL};
PyObject *obj1, *obj4 = 0;
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp
index 57ec15f4150..1b2b18c2c99 100644
--- a/source/blender/freestyle/intern/python/BPy_Operators.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp
@@ -34,6 +34,8 @@
#include "BPy_StrokeShader.h"
#include "BPy_Convert.h"
+#include <sstream>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -76,7 +78,7 @@ PyDoc_STRVAR(Operators_select_doc,
" :arg pred: The predicate expressing this condition.\n"
" :type pred: :class:`UnaryPredicate1D`");
-static PyObject *Operators_select(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_select(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", NULL};
PyObject *obj = 0;
@@ -135,7 +137,7 @@ PyDoc_STRVAR(Operators_chain_doc,
" stopping condition.\n"
" :type pred: :class:`UnaryPredicate1D`");
-static PyObject *Operators_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_chain(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"it", "pred", "modifier", NULL};
PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
@@ -224,7 +226,7 @@ PyDoc_STRVAR(Operators_bidirectional_chain_doc,
" contains the chaining rule.\n"
" :type it: :class:`ChainingIterator`");
-static PyObject *Operators_bidirectional_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_bidirectional_chain(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"it", "pred", NULL};
PyObject *obj1 = 0, *obj2 = 0;
@@ -304,7 +306,7 @@ PyDoc_STRVAR(Operators_sequential_split_doc,
" resolution.)\n"
" :type sampling: float");
-static PyObject *Operators_sequential_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_sequential_split(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"starting_pred", "stopping_pred", "sampling", NULL};
static const char *kwlist_2[] = {"pred", "sampling", NULL};
@@ -411,7 +413,7 @@ PyDoc_STRVAR(Operators_recursive_split_doc,
" resolution.)\n"
" :type sampling: float");
-static PyObject *Operators_recursive_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_recursive_split(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"func", "pred_1d", "sampling", NULL};
static const char *kwlist_2[] = {"func", "pred_0d", "pred_1d", "sampling", NULL};
@@ -486,7 +488,7 @@ PyDoc_STRVAR(Operators_sort_doc,
" :arg pred: The binary predicate used for the comparison.\n"
" :type pred: :class:`BinaryPredicate1D`");
-static PyObject *Operators_sort(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_sort(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", NULL};
PyObject *obj = 0;
@@ -517,7 +519,7 @@ PyDoc_STRVAR(Operators_create_doc,
" :arg shaders: The list of shaders used to shade the strokes.\n"
" :type shaders: list of :class:`StrokeShader` objects");
-static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_create(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", "shaders", NULL};
PyObject *obj1 = 0, *obj2 = 0;
@@ -539,7 +541,15 @@ static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject
PyErr_SetString(PyExc_TypeError, "Operators.create(): 2nd argument must be a list of StrokeShader objects");
return NULL;
}
- shaders.push_back(((BPy_StrokeShader *)py_ss)->ss);
+ StrokeShader *shader = ((BPy_StrokeShader *)py_ss)->ss;
+ if (!shader) {
+ stringstream ss;
+ ss << "Operators.create(): item " << (i + 1)
+ << " of the shaders list is invalid likely due to missing call of StrokeShader.__init__()";
+ PyErr_SetString(PyExc_TypeError, ss.str().c_str());
+ return NULL;
+ }
+ shaders.push_back(shader);
}
if (Operators::create(*(((BPy_UnaryPredicate1D *)obj1)->up1D), shaders) < 0) {
if (!PyErr_Occurred())
@@ -558,7 +568,7 @@ PyDoc_STRVAR(Operators_reset_doc,
" :arg delete_strokes: Delete the strokes that are currently stored.\n"
" :type delete_strokes: bool\n");
-static PyObject *Operators_reset(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_reset(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"delete_strokes", NULL};
PyObject *obj1 = 0;
@@ -583,7 +593,7 @@ PyDoc_STRVAR(Operators_get_viewedge_from_index_doc,
" :return: The ViewEdge object.\n"
" :rtype: :class:`ViewEdge`");
-static PyObject *Operators_get_viewedge_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_viewedge_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -607,7 +617,7 @@ PyDoc_STRVAR(Operators_get_chain_from_index_doc,
" :return: The Chain object.\n"
" :rtype: :class:`Chain`");
-static PyObject *Operators_get_chain_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_chain_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -631,7 +641,7 @@ PyDoc_STRVAR(Operators_get_stroke_from_index_doc,
" :return: The Stroke object.\n"
" :rtype: :class:`Stroke`");
-static PyObject *Operators_get_stroke_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_stroke_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -653,7 +663,7 @@ PyDoc_STRVAR(Operators_get_view_edges_size_doc,
" :return: The number of ViewEdges.\n"
" :rtype: int");
-static PyObject *Operators_get_view_edges_size(BPy_Operators *self)
+static PyObject *Operators_get_view_edges_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getViewEdgesSize());
}
@@ -666,7 +676,7 @@ PyDoc_STRVAR(Operators_get_chains_size_doc,
" :return: The number of Chains.\n"
" :rtype: int");
-static PyObject *Operators_get_chains_size(BPy_Operators *self)
+static PyObject *Operators_get_chains_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getChainsSize());
}
@@ -679,7 +689,7 @@ PyDoc_STRVAR(Operators_get_strokes_size_doc,
" :return: The number of Strokes.\n"
" :rtype: int");
-static PyObject *Operators_get_strokes_size(BPy_Operators *self)
+static PyObject *Operators_get_strokes_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getStrokesSize());
}
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
index be20febba2b..0941efe9df5 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
@@ -93,7 +93,7 @@ static void UnaryFunction0D___dealloc__(BPy_UnaryFunction0D *self)
Py_TYPE(self)->tp_free((PyObject *)self);
}
-static PyObject *UnaryFunction0D___repr__(BPy_UnaryFunction0D *self)
+static PyObject *UnaryFunction0D___repr__(BPy_UnaryFunction0D * /*self*/)
{
return PyUnicode_FromString("UnaryFunction0D");
}
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
index b88d609e48d..1b82c7777c7 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
@@ -87,7 +87,7 @@ static void UnaryFunction1D___dealloc__(BPy_UnaryFunction1D *self)
Py_TYPE(self)->tp_free((PyObject *)self);
}
-static PyObject *UnaryFunction1D___repr__(BPy_UnaryFunction1D *self)
+static PyObject *UnaryFunction1D___repr__(BPy_UnaryFunction1D * /*self*/)
{
return PyUnicode_FromString("UnaryFunction1D");
}
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
index 1ef29792d56..9f0660baa9b 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -188,7 +188,10 @@ static PyObject *CurvePoint_fedge_get(BPy_CurvePoint *self, void *UNUSED(closure
{
SVertex *A = self->cp->A();
Interface0D *B = (Interface0D *)self->cp->B();
- return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B)));
+ // B can be NULL under certain circumstances
+ if (B)
+ return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B)));
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(CurvePoint_t2d_doc,
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
index 5e2130ac8e7..f8d0b34d6a9 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
@@ -49,7 +49,7 @@ PyDoc_STRVAR(ViewVertex_doc,
"Thus, this class can be specialized into two classes, the\n"
":class:`TVertex` class and the :class:`NonTVertex` class.");
-static int ViewVertex_init(BPy_ViewVertex *self, PyObject *args, PyObject *kwds)
+static int ViewVertex_init(BPy_ViewVertex * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
{
PyErr_SetString(PyExc_TypeError, "cannot instantiate abstract class");
return -1;
@@ -82,7 +82,7 @@ PyDoc_STRVAR(ViewVertex_edges_end_doc,
" :return: An orientedViewEdgeIterator pointing after the last ViewEdge.\n"
" :rtype: :class:`orientedViewEdgeIterator`");
-static PyObject *ViewVertex_edges_end(BPy_ViewVertex *self)
+static PyObject *ViewVertex_edges_end(BPy_ViewVertex * /*self*/)
{
#if 0
ViewVertexInternal::orientedViewEdgeIterator ove_it(self->vv->edgesEnd());
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
index ae4fe0764b6..ba773d4f4cf 100644
--- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -166,7 +166,7 @@ static int StrokeVertex_mathutils_check(BaseMathObject *bmo)
return 0;
}
-static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int subtype)
+static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int /*subtype*/)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
bmo->data[0] = (float)self->sv->x();
@@ -174,7 +174,7 @@ static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int subtype)
return 0;
}
-static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int subtype)
+static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int /*subtype*/)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
self->sv->setX((real)bmo->data[0]);
@@ -182,7 +182,7 @@ static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int subtype)
return 0;
}
-static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int subtype, int index)
+static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
switch (index) {
@@ -194,7 +194,7 @@ static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int subtype, in
return 0;
}
-static int StrokeVertex_mathutils_set_index(BaseMathObject *bmo, int subtype, int index)
+static int StrokeVertex_mathutils_set_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
switch (index) {
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
index 7592508902b..4c9e0630d40 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -100,7 +100,7 @@ static int FEdge_init(BPy_FEdge *self, PyObject *args, PyObject *kwds)
/*----------------------FEdge sequence protocol ----------------------------*/
-static Py_ssize_t FEdge_sq_length(BPy_FEdge *self)
+static Py_ssize_t FEdge_sq_length(BPy_FEdge * /*self*/)
{
return 2;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
index a2079c7d685..cf893ad9481 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -99,7 +99,7 @@ static int FEdgeSmooth_mathutils_check(BaseMathObject *bmo)
return 0;
}
-static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int subtype)
+static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int /*subtype*/)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
@@ -109,7 +109,7 @@ static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int subtype)
return 0;
}
-static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int subtype)
+static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int /*subtype*/)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(bmo->data[0], bmo->data[1], bmo->data[2]);
@@ -117,7 +117,7 @@ static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int subtype)
return 0;
}
-static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int subtype, int index)
+static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
@@ -125,7 +125,7 @@ static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int subtype, int
return 0;
}
-static int FEdgeSmooth_mathutils_set_index(BaseMathObject *bmo, int subtype, int index)
+static int FEdgeSmooth_mathutils_set_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
index 46294c07b66..c4fead6a4e4 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
@@ -31,7 +31,6 @@
extern "C" {
#endif
-struct MTex;
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
index 46efeae9f12..05fc043822f 100644
--- a/source/blender/freestyle/intern/stroke/Predicates1D.h
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -471,7 +471,7 @@ public:
}
/*! The () operator. */
- int operator()(Interface1D& i1, Interface1D& i2)
+ int operator()(Interface1D& /*i1*/, Interface1D& /*i2*/)
{
result = true;
return 0;
@@ -490,7 +490,7 @@ public:
}
/*! The () operator. */
- int operator()(Interface1D& i1, Interface1D& i2)
+ int operator()(Interface1D& /*i1*/, Interface1D& /*i2*/)
{
result = false;
return 0;
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index 244b20f6b89..b4a3646edef 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -752,12 +752,12 @@ Interface0DIterator Stroke::verticesEnd()
return ret;
}
-Interface0DIterator Stroke::pointsBegin(float t)
+Interface0DIterator Stroke::pointsBegin(float /*t*/)
{
return verticesBegin(); // FIXME
}
-Interface0DIterator Stroke::pointsEnd(float t)
+Interface0DIterator Stroke::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 60193590944..ddb79b2df0b 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -51,6 +51,8 @@ extern "C" {
#include "BKE_text.h"
#include "BPY_extern.h"
+
+#include "bpy_util.h"
}
namespace Freestyle {
@@ -105,6 +107,26 @@ public:
return 0;
}
+ int interpretString(const string& str, const string& name)
+ {
+ ReportList *reports = CTX_wm_reports(_context);
+
+ BKE_reports_clear(reports);
+
+ if (BPY_string_exec(_context, str.c_str()) != 0) {
+ BPy_errors_to_report(reports);
+ cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
+ cerr << "Name: " << name << endl;
+ cerr << "Errors: " << endl;
+ BKE_reports_print(reports, RPT_ERROR);
+ return 1;
+ }
+
+ BKE_reports_clear(reports);
+
+ return 0;
+ }
+
int interpretText(struct Text *text, const string& name)
{
ReportList *reports = CTX_wm_reports(_context);
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
index f770bf6843f..ae22a26ec9b 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
@@ -71,18 +71,18 @@ void BoxGrid::Cell::indexPolygons()
// Iterator
//////////////////
-BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real epsilon)
+BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real /*epsilon*/)
: _target(grid.transform(center)), _foundOccludee(false)
{
// Find target cell
_cell = grid.findCell(_target);
- #if BOX_GRID_LOGGING
+#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
}
- #endif
+#endif
// Set iterator
_current = _cell->faces.begin();
@@ -122,7 +122,7 @@ BoxGrid::BoxGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *
BoxGrid::~BoxGrid() {}
-void BoxGrid::assignCells (OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+void BoxGrid::assignCells (OccluderSource& /*source*/, GridDensityProvider& density, ViewMap *viewMap)
{
_cellSize = density.cellSize();
_cellsX = density.cellsX();
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.h b/source/blender/freestyle/intern/view_map/BoxGrid.h
index 0ef4ce37b11..b8e751d041d 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.h
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.h
@@ -303,11 +303,11 @@ inline void BoxGrid::Iterator::reportDepth(Vec3r origin, Vec3r u, real t)
// The reported depth is the length of a ray in camera space
// We need to convert it into a Z-value in grid space
real depth = -(origin + (u * t))[2];
- #if BOX_GRID_LOGGING
+#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
std::cout << "\t\tReporting depth of occluder/ee: " << depth;
}
- #endif
+#endif
if (depth > _target[2]) {
#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
diff --git a/source/blender/freestyle/intern/view_map/Interface1D.cpp b/source/blender/freestyle/intern/view_map/Interface1D.cpp
index 985310e52b5..f4abad11479 100644
--- a/source/blender/freestyle/intern/view_map/Interface1D.cpp
+++ b/source/blender/freestyle/intern/view_map/Interface1D.cpp
@@ -42,13 +42,13 @@ Interface0DIterator Interface1D::verticesEnd()
return Interface0DIterator();
}
-Interface0DIterator Interface1D::pointsBegin(float t)
+Interface0DIterator Interface1D::pointsBegin(float /*t*/)
{
PyErr_SetString(PyExc_TypeError, "method pointsBegin() not properly overridden");
return Interface0DIterator();
}
-Interface0DIterator Interface1D::pointsEnd(float t)
+Interface0DIterator Interface1D::pointsEnd(float /*t*/)
{
PyErr_SetString(PyExc_TypeError, "method pointsEnd() not properly overridden");
return Interface0DIterator();
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 94b00157ccd..a80fea0342f 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1122,12 +1122,12 @@ Interface0DIterator FEdge::verticesEnd()
return ret;
}
-Interface0DIterator FEdge::pointsBegin(float t)
+Interface0DIterator FEdge::pointsBegin(float /*t*/)
{
return verticesBegin();
}
-Interface0DIterator FEdge::pointsEnd(float t)
+Interface0DIterator FEdge::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
index 60ad7daea0a..10c88190cb3 100644
--- a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
@@ -72,18 +72,18 @@ void SphericalGrid::Cell::indexPolygons()
// Iterator
//////////////////
-SphericalGrid::Iterator::Iterator(SphericalGrid& grid, Vec3r& center, real epsilon)
+SphericalGrid::Iterator::Iterator(SphericalGrid& grid, Vec3r& center, real /*epsilon*/)
: _target(SphericalGrid::Transform::sphericalProjection(center)), _foundOccludee(false)
{
// Find target cell
_cell = grid.findCell(_target);
- #if SPHERICAL_GRID_LOGGING
+#if SPHERICAL_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
}
- #endif
+#endif
// Set iterator
_current = _cell->faces.begin();
@@ -120,7 +120,7 @@ SphericalGrid::SphericalGrid(OccluderSource& source, GridDensityProvider& densit
SphericalGrid::~SphericalGrid() {}
-void SphericalGrid::assignCells(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+void SphericalGrid::assignCells(OccluderSource& /*source*/, GridDensityProvider& density, ViewMap *viewMap)
{
_cellSize = density.cellSize();
_cellsX = density.cellsX();
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp
index 6bb0082e379..52769413e79 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp
@@ -701,12 +701,12 @@ Interface0DIterator ViewEdge::verticesEnd()
return ret;
}
-Interface0DIterator ViewEdge::pointsBegin(float t)
+Interface0DIterator ViewEdge::pointsBegin(float /*t*/)
{
return verticesBegin();
}
-Interface0DIterator ViewEdge::pointsEnd(float t)
+Interface0DIterator ViewEdge::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 8adc2fa66fd..932c23698dc 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -56,7 +56,7 @@ static const Global &_global = G;
using namespace std;
template <typename G, typename I>
-static void findOccludee(FEdge *fe, G& grid, I& occluders, real epsilon, WFace **oaWFace,
+static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace,
Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
@@ -169,7 +169,7 @@ static void findOccludee(FEdge *fe, G& grid, I& occluders, real epsilon, WFace *
}
template <typename G, typename I>
-static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaFace)
+static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace)
{
Vec3r A;
Vec3r edge;
@@ -205,7 +205,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace *
// computeVisibility takes a pointer to foundOccluders, instead of using a reference,
// so that computeVeryFastVisibility can skip the AddOccluders step with minimal overhead.
template <typename G, typename I>
-static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaWFace,
+static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaWFace,
set<ViewShape*> *foundOccluders)
{
int qi = 0;
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
index 08b2fde8f31..36497bf8d22 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
@@ -145,7 +145,7 @@ public:
* The viewport. 4 real array: origin.x, origin.y, width, length
*/
inline void setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4],
- const int iViewport[4], real iFocalLength, real iAspect, real iFovy)
+ const int iViewport[4], real iFocalLength, real /*iAspect*/, real /*iFovy*/)
{
_orthographicProjection = (iProjectionMatrix[3][3] != 0.0);
SilhouetteGeomEngine::setTransform(iModelViewMatrix, iProjectionMatrix, iViewport, iFocalLength);
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
index c9f2f3badab..df990a3468f 100644
--- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
@@ -221,7 +221,7 @@ void WingedEdgeBuilder::buildWVertices(WShape& shape, const real *vertices, unsi
}
}
-void WingedEdgeBuilder::buildTriangleStrip(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+void WingedEdgeBuilder::buildTriangleStrip(const real * /*vertices*/, const real *normals, vector<FrsMaterial>& /*iMaterials*/,
const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
const unsigned *tindices, const unsigned nvertices)
@@ -296,15 +296,15 @@ void WingedEdgeBuilder::buildTriangleStrip(const real *vertices, const real *nor
}
}
-void WingedEdgeBuilder::buildTriangleFan(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
- const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
- const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
- const unsigned *tindices, const unsigned nvertices)
+void WingedEdgeBuilder::buildTriangleFan(const real * /*vertices*/, const real * /*normals*/, vector<FrsMaterial>& /*iMaterials*/,
+ const real * /*texCoords*/, const IndexedFaceSet::FaceEdgeMark * /*iFaceEdgeMarks*/,
+ const unsigned * /*vindices*/, const unsigned * /*nindices*/, const unsigned * /*mindices*/,
+ const unsigned * /*tindices*/, const unsigned /*nvertices*/)
{
// Nothing to be done
}
-void WingedEdgeBuilder::buildTriangles(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+void WingedEdgeBuilder::buildTriangles(const real * /*vertices*/, const real *normals, vector<FrsMaterial>& /*iMaterials*/,
const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
const unsigned *tindices, const unsigned nvertices)
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index b5d9028a8ae..23a2b77d1e7 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -57,10 +57,16 @@ set(SRC
intern/gpu_compositing.c
intern/gpu_debug.c
+ shaders/gpu_program_smoke_frag.glsl
+ shaders/gpu_program_smoke_color_frag.glsl
+
shaders/gpu_shader_fx_lib.glsl
shaders/gpu_shader_fx_ssao_frag.glsl
shaders/gpu_shader_fx_dof_frag.glsl
shaders/gpu_shader_fx_dof_vert.glsl
+ shaders/gpu_shader_fx_dof_hq_frag.glsl
+ shaders/gpu_shader_fx_dof_hq_vert.glsl
+ shaders/gpu_shader_fx_dof_hq_geo.glsl
shaders/gpu_shader_fx_vert.glsl
shaders/gpu_shader_material.glsl
shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -86,6 +92,8 @@ set(SRC
intern/gpu_private.h
)
+data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
@@ -99,6 +107,9 @@ data_to_c_simple(shaders/gpu_shader_fx_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index e9b600a9267..a8630d0c5be 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -42,19 +42,17 @@
struct BMesh;
struct CCGElem;
struct CCGKey;
-struct CustomData;
struct DMFlagMat;
struct DerivedMesh;
-struct GHash;
struct GSet;
struct GPUVertPointLink;
struct PBVH;
typedef struct GPUBuffer {
- int size; /* in bytes */
- void *pointer; /* used with vertex arrays */
- unsigned int id; /* used with vertex buffer objects */
- bool use_vbo; /* true for VBOs, false for vertex arrays */
+ int size; /* in bytes */
+ void *pointer; /* used with vertex arrays */
+ unsigned int id; /* used with vertex buffer objects */
+ bool use_vbo; /* true for VBOs, false for vertex arrays */
} GPUBuffer;
typedef struct GPUBufferMaterial {
@@ -115,6 +113,10 @@ typedef struct GPUDrawObject {
/* caches of the original DerivedMesh values */
int totvert;
int totedge;
+
+ int loose_edge_offset;
+ int tot_loose_edge_drawn;
+ int tot_edge_drawn;
} GPUDrawObject;
/* used for GLSL materials */
diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h
index 93f1bc64922..04e89da00a7 100644
--- a/source/blender/gpu/GPU_compositing.h
+++ b/source/blender/gpu/GPU_compositing.h
@@ -42,17 +42,15 @@ struct GPUDOFSettings;
struct GPUSSAOSettings;
struct GPUOffScreen;
struct GPUFXSettings;
-struct RegionView3D;
struct rcti;
struct Scene;
-struct View3D;
enum eGPUFXFlags;
/**** Public API *****/
typedef enum GPUFXShaderEffect {
/* Screen space ambient occlusion shader */
- GPU_SHADER_FX_SSAO = 1,
+ GPU_SHADER_FX_SSAO = 1,
/* depth of field passes. Yep, quite a complex effect */
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2,
@@ -61,11 +59,16 @@ typedef enum GPUFXShaderEffect {
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5,
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6,
- GPU_SHADER_FX_DEPTH_RESOLVE = 7,
+ /* high quality */
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9,
+
+ GPU_SHADER_FX_DEPTH_RESOLVE = 10,
} GPUFXShaderEffect;
/* keep in synch with enum above! */
-#define MAX_FX_SHADERS 8
+#define MAX_FX_SHADERS 11
/* generate a new FX compositor */
GPUFX *GPU_fx_compositor_create(void);
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index a74c0e7c67b..f89df2b54aa 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -63,7 +63,7 @@ void gpu_assert_no_gl_errors(const char *file, int line, const char *str);
#ifdef WITH_GPU_DEBUG
/* inserts a debug marker message for the debug context messaging system */
-void gpu_string_marker (size_t size, const char *str);
+void gpu_string_marker(size_t size, const char *str);
# define GPU_STRING_MARKER(size, str) gpu_string_marker((size), (str))
#else /* WITH_GPU_DEBUG */
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 57aa7f202b0..845ae9d2b30 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -36,6 +36,7 @@
extern "C" {
#endif
+struct ImBuf;
struct Image;
struct ImageUser;
struct MTFace;
@@ -84,6 +85,7 @@ int GPU_get_material_alpha_blend(void);
int GPU_set_tpage(struct MTFace *tface, int mipmap, int transp);
void GPU_clear_tpage(bool force);
+
/* Lights
* - returns how many lights were enabled
* - this affects fixed functions materials and texface, not glsl */
@@ -102,11 +104,11 @@ void GPU_render_text(struct MTFace *tface, int mode,
/* Mipmap settings
* - these will free textures on changes */
-void GPU_set_mipmap(int mipmap);
-int GPU_get_mipmap(void);
-void GPU_set_linear_mipmap(int linear);
-int GPU_get_linear_mipmap(void);
-void GPU_paint_set_mipmap(int mipmap);
+void GPU_set_mipmap(bool mipmap);
+bool GPU_get_mipmap(void);
+void GPU_set_linear_mipmap(bool linear);
+bool GPU_get_linear_mipmap(void);
+void GPU_paint_set_mipmap(bool mipmap);
/* Anisotropic filtering settings
* - these will free textures on changes */
@@ -119,7 +121,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
/* Image updates and free
* - these deal with images bound as opengl textures */
-void GPU_paint_update_image(struct Image *ima, int x, int y, int w, int h);
+void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h);
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data);
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 228bea14e00..f3927ba960b 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -52,46 +52,56 @@ typedef struct GPUOffScreen GPUOffScreen;
struct GPUShader;
typedef struct GPUShader GPUShader;
+struct GPUProgram;
+typedef struct GPUProgram GPUProgram;
+
/* GPU extensions support */
void GPU_extensions_disable(void);
-int GPU_glsl_support(void);
-int GPU_non_power_of_two_support(void);
-int GPU_vertex_buffer_support(void);
-int GPU_display_list_support(void);
+bool GPU_glsl_support(void);
+bool GPU_non_power_of_two_support(void);
+bool GPU_vertex_buffer_support(void);
+bool GPU_display_list_support(void);
+bool GPU_bicubic_bump_support(void);
+bool GPU_geometry_shader_support(void);
+bool GPU_instanced_drawing_support(void);
+
+int GPU_max_texture_size(void);
int GPU_color_depth(void);
-void GPU_code_generate_glsl_lib(void);
-int GPU_bicubic_bump_support(void);
-int GPU_max_texture_size (void);
+void GPU_get_dfdy_factors(float fac[2]);
+bool GPU_mem_stats_supported(void);
+void GPU_mem_stats_get(int *totalmem, int *freemem);
+
+void GPU_code_generate_glsl_lib(void);
/* GPU Types */
typedef enum GPUDeviceType {
- GPU_DEVICE_NVIDIA = (1<<0),
- GPU_DEVICE_ATI = (1<<1),
- GPU_DEVICE_INTEL = (1<<2),
- GPU_DEVICE_SOFTWARE = (1<<3),
- GPU_DEVICE_UNKNOWN = (1<<4),
- GPU_DEVICE_ANY = (0xff)
+ GPU_DEVICE_NVIDIA = (1<<0),
+ GPU_DEVICE_ATI = (1<<1),
+ GPU_DEVICE_INTEL = (1<<2),
+ GPU_DEVICE_SOFTWARE = (1<<3),
+ GPU_DEVICE_UNKNOWN = (1<<4),
+ GPU_DEVICE_ANY = (0xff)
} GPUDeviceType;
typedef enum GPUOSType {
- GPU_OS_WIN = (1<<8),
- GPU_OS_MAC = (1<<9),
- GPU_OS_UNIX = (1<<10),
- GPU_OS_ANY = (0xff00)
+ GPU_OS_WIN = (1<<8),
+ GPU_OS_MAC = (1<<9),
+ GPU_OS_UNIX = (1<<10),
+ GPU_OS_ANY = (0xff00)
} GPUOSType;
typedef enum GPUDriverType {
- GPU_DRIVER_OFFICIAL = (1<<16),
+ GPU_DRIVER_OFFICIAL = (1<<16),
GPU_DRIVER_OPENSOURCE = (1<<17),
- GPU_DRIVER_SOFTWARE = (1<<18),
- GPU_DRIVER_ANY = (0xff0000)
+ GPU_DRIVER_SOFTWARE = (1<<18),
+ GPU_DRIVER_ANY = (0xff0000)
} GPUDriverType;
-int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
+bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
/* GPU Texture
* - always returns unsigned char RGBA textures
@@ -113,13 +123,13 @@ typedef enum GPUHDRType {
GPU_HDR_FULL_FLOAT = (1 << 1),
} GPUHDRType;
-GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, GPUHDRType hdr, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels);
+GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_from_blender(struct Image *ima,
struct ImageUser *iuser, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
@@ -134,14 +144,14 @@ void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int number);
void GPU_texture_unbind(GPUTexture *tex);
-void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter);
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
-int GPU_texture_target(GPUTexture *tex);
-int GPU_texture_opengl_width(GPUTexture *tex);
-int GPU_texture_opengl_height(GPUTexture *tex);
-int GPU_texture_opengl_bindcode(GPUTexture *tex);
+int GPU_texture_target(const GPUTexture *tex);
+int GPU_texture_opengl_width(const GPUTexture *tex);
+int GPU_texture_opengl_height(const GPUTexture *tex);
+int GPU_texture_opengl_bindcode(const GPUTexture *tex);
/* GPU Framebuffer
* - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
@@ -174,14 +184,26 @@ void GPU_offscreen_free(GPUOffScreen *ofs);
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
-int GPU_offscreen_width(GPUOffScreen *ofs);
-int GPU_offscreen_height(GPUOffScreen *ofs);
+int GPU_offscreen_width(const GPUOffScreen *ofs);
+int GPU_offscreen_height(const GPUOffScreen *ofs);
+
+/* Builtin/Non-generated shaders */
+typedef enum GPUProgramType {
+ GPU_PROGRAM_TYPE_FRAGMENT = 0
+} GPUProgramType;
+
+
+GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
+void GPU_program_free(GPUProgram *program);
+void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
+void GPU_program_bind(GPUProgram *);
+void GPU_program_unbind(GPUProgram *);
/* GPU Shader
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines);
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
@@ -190,25 +212,35 @@ void GPU_shader_unbind(void);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
int arraysize, const float *value);
+void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
+ int arraysize, const int *value);
+
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
/* Builtin/Non-generated shaders */
typedef enum GPUBuiltinShader {
- GPU_SHADER_VSM_STORE = (1<<0),
- GPU_SHADER_SEP_GAUSSIAN_BLUR = (1<<1),
+ GPU_SHADER_VSM_STORE = 0,
+ GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
} GPUBuiltinShader;
+typedef enum GPUBuiltinProgram {
+ GPU_PROGRAM_SMOKE = 0,
+ GPU_PROGRAM_SMOKE_COLORED = 1,
+} GPUBuiltinProgram;
+
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
+GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
void GPU_shader_free_builtin_shaders(void);
/* Vertex attributes for shaders */
-#define GPU_MAX_ATTRIB 32
+#define GPU_MAX_ATTRIB 32
typedef struct GPUVertexAttribs {
struct {
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 64ce936e64a..ee6e02547e7 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -45,10 +45,7 @@ struct Image;
struct ImageUser;
struct Material;
struct Object;
-struct Lamp;
struct Image;
-struct bNode;
-struct LinkNode;
struct Scene;
struct SceneRenderLayer;
struct GPUVertexAttribs;
@@ -92,7 +89,7 @@ typedef enum GPUBuiltin {
GPU_VIEW_NORMAL = (1 << 5),
GPU_OBCOLOR = (1 << 6),
GPU_AUTO_BUMPSCALE = (1 << 7),
- GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
+ GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -124,31 +121,62 @@ typedef struct GPUNodeStack {
short sockettype;
} GPUNodeStack;
+
+#define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000)
+
+#define GPU_DYNAMIC_GROUP_MISC 0x00010000
+#define GPU_DYNAMIC_GROUP_LAMP 0x00020000
+#define GPU_DYNAMIC_GROUP_OBJECT 0x00030000
+#define GPU_DYNAMIC_GROUP_SAMPLER 0x00040000
+#define GPU_DYNAMIC_GROUP_MIST 0x00050000
+#define GPU_DYNAMIC_GROUP_WORLD 0x00060000
+#define GPU_DYNAMIC_GROUP_MAT 0x00070000
+
typedef enum GPUDynamicType {
- GPU_DYNAMIC_NONE = 0,
- GPU_DYNAMIC_OBJECT_VIEWMAT = 1,
- GPU_DYNAMIC_OBJECT_MAT = 2,
- GPU_DYNAMIC_OBJECT_VIEWIMAT = 3,
- GPU_DYNAMIC_OBJECT_IMAT = 4,
- GPU_DYNAMIC_OBJECT_COLOR = 5,
- GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 15,
-
- GPU_DYNAMIC_LAMP_FIRST = 6,
- GPU_DYNAMIC_LAMP_DYNVEC = 6,
- GPU_DYNAMIC_LAMP_DYNCO = 7,
- GPU_DYNAMIC_LAMP_DYNIMAT = 8,
- GPU_DYNAMIC_LAMP_DYNPERSMAT = 9,
- GPU_DYNAMIC_LAMP_DYNENERGY = 10,
- GPU_DYNAMIC_LAMP_DYNCOL = 11,
- GPU_DYNAMIC_LAMP_LAST = 11,
- GPU_DYNAMIC_SAMPLER_2DBUFFER = 12,
- GPU_DYNAMIC_SAMPLER_2DIMAGE = 13,
- GPU_DYNAMIC_SAMPLER_2DSHADOW = 14,
- GPU_DYNAMIC_LAMP_DISTANCE = 16,
- GPU_DYNAMIC_LAMP_ATT1 = 17,
- GPU_DYNAMIC_LAMP_ATT2 = 18,
- GPU_DYNAMIC_LAMP_SPOTSIZE = 19,
- GPU_DYNAMIC_LAMP_SPOTBLEND = 20,
+
+ GPU_DYNAMIC_NONE = 0,
+
+ GPU_DYNAMIC_OBJECT_VIEWMAT = 1 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_MAT = 2 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_VIEWIMAT = 3 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_IMAT = 4 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_COLOR = 5 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 6 | GPU_DYNAMIC_GROUP_OBJECT,
+
+ GPU_DYNAMIC_LAMP_DYNVEC = 1 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNCO = 2 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNIMAT = 3 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNPERSMAT = 4 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNENERGY = 5 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNCOL = 6 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DISTANCE = 7 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_ATT1 = 8 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP,
+
+ GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER,
+ GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER,
+ GPU_DYNAMIC_SAMPLER_2DSHADOW = 3 | GPU_DYNAMIC_GROUP_SAMPLER,
+
+ GPU_DYNAMIC_MIST_ENABLE = 1 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_START = 2 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_DISTANCE = 3 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_INTENSITY = 4 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_TYPE = 5 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_COLOR = 6 | GPU_DYNAMIC_GROUP_MIST,
+
+ GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD,
+ GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD,
+
+ GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_SPECRGB = 3 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_SPEC = 4 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_HARD = 5 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT
} GPUDynamicType;
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
@@ -181,7 +209,7 @@ bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, stru
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 obcol[4], float autobumpscale);
void GPU_material_unbind(GPUMaterial *material);
-int GPU_material_bound(GPUMaterial *material);
+bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
GPUMatType GPU_Material_get_type(GPUMaterial *material);
@@ -213,7 +241,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr);
typedef enum GPUDataType {
GPU_DATA_NONE = 0,
- GPU_DATA_1I = 1, // 1 integer
+ GPU_DATA_1I = 1, /* 1 integer */
GPU_DATA_1F = 2,
GPU_DATA_2F = 3,
GPU_DATA_3F = 4,
@@ -226,23 +254,23 @@ typedef enum GPUDataType {
/* this structure gives information of each uniform found in the shader */
typedef struct GPUInputUniform {
struct GPUInputUniform *next, *prev;
- char varname[32]; /* name of uniform in shader */
- GPUDynamicType type; /* type of uniform, data format and calculation derive from it */
- GPUDataType datatype; /* type of uniform data */
- struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
- struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
- int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
- unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
- int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */
+ char varname[32]; /* name of uniform in shader */
+ GPUDynamicType type; /* type of uniform, data format and calculation derive from it */
+ GPUDataType datatype; /* type of uniform data */
+ struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
+ struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
+ int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
+ unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
+ int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */
} GPUInputUniform;
typedef struct GPUInputAttribute {
struct GPUInputAttribute *next, *prev;
- char varname[32]; /* name of attribute in shader */
- int type; /* from CustomData.type, data type derives from it */
- GPUDataType datatype; /* type of attribute data */
- const char *name; /* layer name */
- int number; /* generic attribute number */
+ char varname[32]; /* name of attribute in shader */
+ int type; /* from CustomData.type, data type derives from it */
+ GPUDataType datatype; /* type of attribute data */
+ const char *name; /* layer name */
+ int number; /* generic attribute number */
} GPUInputAttribute;
typedef struct GPUShaderExport {
@@ -273,6 +301,12 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
int GPU_lamp_shadow_layer(GPULamp *lamp);
GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy);
+/* World */
+void GPU_mist_update_enable(short enable);
+void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]);
+void GPU_horizon_update_color(float color[3]);
+void GPU_ambient_update_color(float color[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_simple_shader.h b/source/blender/gpu/GPU_simple_shader.h
index c8fb1f09b04..239296209b4 100644
--- a/source/blender/gpu/GPU_simple_shader.h
+++ b/source/blender/gpu/GPU_simple_shader.h
@@ -42,11 +42,11 @@ extern "C" {
typedef enum GPUSimpleShaderOption {
GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */
- GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
- GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
- GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
+ GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
+ GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
+ GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
- GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */
+ GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */
GPU_SHADER_OPTIONS_NUM = 5,
GPU_SHADER_OPTION_COMBINATIONS = (1<<GPU_SHADER_OPTIONS_NUM)
} GPUSimpleShaderOption;
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index f52b39dba3b..ff5fb42c021 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -63,9 +63,14 @@ if env['WITH_BF_DDS']:
# generated data files
import os
sources.extend((
+ os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_vert.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_geo.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_vert.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_depth_resolve.glsl.c"),
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index e622943597a..62843f0905f 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -383,8 +383,9 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
-/* currently unused */
-// #define USE_GPU_POINT_LINK
+#if 0 /* currently unused */
+# define USE_GPU_POINT_LINK
+#endif
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
@@ -452,7 +453,7 @@ static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int to
int i, *mat_orig_to_new;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
- "GPUDrawObject.mat_orig_to_new");
+ "GPUDrawObject.mat_orig_to_new");
/* allocate the array and space for links */
gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
"GPUDrawObject.vert_points");
@@ -939,17 +940,62 @@ static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, in
static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
{
- MEdge *medge;
+ MEdge *medge, *medge_base;
unsigned int *varray = (unsigned int *)varray_;
- int i, totedge;
+ int i, totedge, iloose, inorm, iloosehidden, inormhidden;
+ int tot_loose_hidden = 0, tot_loose = 0;
+ int tot_hidden = 0, tot = 0;
- medge = dm->getEdgeArray(dm);
+ medge_base = medge = dm->getEdgeArray(dm);
totedge = dm->getNumEdges(dm);
for (i = 0; i < totedge; i++, medge++) {
- varray[i * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[i * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
+ if (medge->flag & ME_EDGEDRAW) {
+ if (medge->flag & ME_LOOSEEDGE) tot_loose++;
+ else tot++;
+ }
+ else {
+ if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++;
+ else tot_hidden++;
+ }
+ }
+
+ inorm = 0;
+ inormhidden = tot;
+ iloose = tot + tot_hidden;
+ iloosehidden = iloose + tot_loose;
+
+ medge = medge_base;
+ for (i = 0; i < totedge; i++, medge++) {
+ if (medge->flag & ME_EDGEDRAW) {
+ if (medge->flag & ME_LOOSEEDGE) {
+ varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index;
+ varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
+ iloose++;
+ }
+ else {
+ varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index;
+ varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
+ inorm++;
+ }
+ }
+ else {
+ if (medge->flag & ME_LOOSEEDGE) {
+ varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
+ varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
+ iloosehidden++;
+ }
+ else {
+ varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
+ varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
+ inormhidden++;
+ }
+ }
}
+
+ dm->drawObject->tot_loose_edge_drawn = tot_loose;
+ dm->drawObject->loose_edge_offset = tot + tot_hidden;
+ dm->drawObject->tot_edge_drawn = tot;
}
static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
@@ -1007,7 +1053,7 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
{GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
{GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
- {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4},
+ {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4},
{GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
};
@@ -1498,6 +1544,7 @@ struct GPU_PBVH_Buffers {
bool use_matcaps;
float diffuse_color[4];
};
+
typedef enum {
VBO_ENABLED,
VBO_DISABLED
@@ -1577,8 +1624,8 @@ static void gpu_color_from_mask_quad_set(const CCGKey *key,
}
void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert,
- int *vert_indices, int totvert, const float *vmask,
- int (*face_vert_indices)[4], bool show_diffuse_color)
+ int *vert_indices, int totvert, const float *vmask,
+ int (*face_vert_indices)[4], bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j, k;
@@ -1715,9 +1762,9 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert,
}
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4],
- MFace *mface, MVert *mvert,
- int *face_indices,
- int totface)
+ MFace *mface, MVert *mvert,
+ int *face_indices,
+ int totface)
{
GPU_PBVH_Buffers *buffers;
unsigned short *tri_data;
@@ -1807,8 +1854,8 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4],
}
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)
+ 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;
@@ -1921,51 +1968,51 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
/* Build the element array buffer of grid indices using either
* unsigned shorts or unsigned ints. */
#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \
- { \
- type_ *tri_data; \
- int offset = 0; \
- int i, j, k; \
- \
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
- sizeof(type_) * (tot_quad_) * 6, NULL, \
- GL_STATIC_DRAW_ARB); \
- \
- /* Fill the buffer */ \
- tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
- GL_WRITE_ONLY_ARB); \
- if (tri_data) { \
- for (i = 0; i < totgrid; ++i) { \
- BLI_bitmap *gh = NULL; \
- if (grid_hidden) \
- gh = grid_hidden[(grid_indices)[i]]; \
- \
- for (j = 0; j < gridsize - 1; ++j) { \
- for (k = 0; k < gridsize - 1; ++k) { \
- /* Skip hidden grid face */ \
- if (gh && \
- paint_is_grid_face_hidden(gh, \
- gridsize, k, j)) \
- continue; \
- \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- \
- *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- } \
- } \
- \
- offset += gridsize * gridsize; \
- } \
- glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \
- } \
- else { \
- glDeleteBuffersARB(1, &(buffer_)); \
- (buffer_) = 0; \
- } \
- } (void)0
+ { \
+ type_ *tri_data; \
+ int offset = 0; \
+ int i, j, k; \
+ \
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
+ sizeof(type_) * (tot_quad_) * 6, NULL, \
+ GL_STATIC_DRAW_ARB); \
+ \
+ /* Fill the buffer */ \
+ tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
+ GL_WRITE_ONLY_ARB); \
+ if (tri_data) { \
+ for (i = 0; i < totgrid; ++i) { \
+ BLI_bitmap *gh = NULL; \
+ if (grid_hidden) \
+ gh = grid_hidden[(grid_indices)[i]]; \
+ \
+ for (j = 0; j < gridsize - 1; ++j) { \
+ for (k = 0; k < gridsize - 1; ++k) { \
+ /* Skip hidden grid face */ \
+ if (gh && \
+ paint_is_grid_face_hidden(gh, \
+ gridsize, k, j)) \
+ continue; \
+ \
+ *(tri_data++) = offset + j * gridsize + k + 1; \
+ *(tri_data++) = offset + j * gridsize + k; \
+ *(tri_data++) = offset + (j + 1) * gridsize + k; \
+ \
+ *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \
+ *(tri_data++) = offset + j * gridsize + k + 1; \
+ *(tri_data++) = offset + (j + 1) * gridsize + k; \
+ } \
+ } \
+ \
+ offset += gridsize * gridsize; \
+ } \
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \
+ } \
+ else { \
+ glDeleteBuffersARB(1, &(buffer_)); \
+ (buffer_) = 0; \
+ } \
+ } (void)0
/* end FILL_QUAD_BUFFER */
static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
@@ -2021,7 +2068,7 @@ static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *to
}
GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- BLI_bitmap **grid_hidden, int gridsize)
+ BLI_bitmap **grid_hidden, int gridsize)
{
GPU_PBVH_Buffers *buffers;
int totquad;
@@ -2103,7 +2150,6 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset),
diffuse_color,
vd->color);
-
/* Assign index for use in the triangle index buffer */
/* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
@@ -2153,11 +2199,11 @@ 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)
+ BMesh *bm,
+ GSet *bm_faces,
+ GSet *bm_unique_verts,
+ GSet *bm_other_verts,
+ bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
void *tri_data;
@@ -2204,8 +2250,8 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
/* Initialize vertex buffer */
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
- sizeof(VertexBufferFormat) * totvert,
- NULL, GL_STATIC_DRAW_ARB);
+ sizeof(VertexBufferFormat) * totvert,
+ NULL, GL_STATIC_DRAW_ARB);
/* Fill vertex buffer */
vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
@@ -2246,7 +2292,9 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
float fmask = 0;
int i;
- // BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3);
+#if 0
+ BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3);
+#endif
BM_face_as_array_vert_tri(f, v);
/* Average mask value */
@@ -2666,7 +2714,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
}
else if (buffers->use_bmesh) {
- /* due to dynamc nature of dyntopo, only get first material */
+ /* due to dynamic nature of dyntopo, only get first material */
if (BLI_gset_size(bm_faces) > 0) {
GSetIterator gs_iter;
BMFace *f;
@@ -2717,7 +2765,7 @@ static void gpu_pbvh_buffer_free_intern(GLuint id)
if (pool->maxpbvhsize == pool->totpbvhbufids) {
pool->maxpbvhsize += MAX_FREE_GPU_BUFF_IDS;
pool->pbvhbufids = MEM_reallocN(pool->pbvhbufids,
- sizeof(*pool->pbvhbufids) * pool->maxpbvhsize);
+ sizeof(*pool->pbvhbufids) * pool->maxpbvhsize);
}
/* insert the buffer into the beginning of the pool */
@@ -2742,33 +2790,33 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
{
const float quads[4][4][3] = {
- {
- {min[0], min[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {min[0], min[1], max[2]}
- },
-
- {
- {min[0], min[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {min[0], min[1], max[2]}
- },
-
- {
- {max[0], max[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {max[0], max[1], max[2]}
- },
-
- {
- {max[0], max[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {max[0], max[1], max[2]}
- },
+ {
+ {min[0], min[1], min[2]},
+ {max[0], min[1], min[2]},
+ {max[0], min[1], max[2]},
+ {min[0], min[1], max[2]}
+ },
+
+ {
+ {min[0], min[1], min[2]},
+ {min[0], max[1], min[2]},
+ {min[0], max[1], max[2]},
+ {min[0], min[1], max[2]}
+ },
+
+ {
+ {max[0], max[1], min[2]},
+ {max[0], min[1], min[2]},
+ {max[0], min[1], max[2]},
+ {max[0], max[1], max[2]}
+ },
+
+ {
+ {max[0], max[1], min[2]},
+ {min[0], max[1], min[2]},
+ {min[0], max[1], max[2]},
+ {max[0], max[1], max[2]}
+ },
};
if (leaf)
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 47d2ac2d2e5..944011879b5 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -46,7 +46,7 @@
#include "GPU_material.h"
#include "GPU_extensions.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" /* for intptr_t support */
#include "gpu_codegen.h"
@@ -90,9 +90,11 @@ static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
/* GLSL code parsing for finding function definitions.
* These are stored in a hash for lookup when creating a material. */
-static GHash *FUNCTION_HASH= NULL;
-/* static char *FUNCTION_PROTOTYPES= NULL;
- * static GPUShader *FUNCTION_LIB= NULL;*/
+static GHash *FUNCTION_HASH = NULL;
+#if 0
+static char *FUNCTION_PROTOTYPES = NULL;
+static GPUShader *FUNCTION_LIB = NULL;
+#endif
static int gpu_str_prefix(const char *str, const char *prefix)
{
@@ -116,8 +118,8 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
break;
else {
- if (token && len < max-1) {
- *token= *str;
+ if (token && len < max - 1) {
+ *token = *str;
token++;
len++;
}
@@ -126,7 +128,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
}
if (token)
- *token= '\0';
+ *token = '\0';
/* skip the next special characters:
* note the missing ')' */
@@ -165,10 +167,10 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
code = gpu_str_skip_token(code, NULL, 0);
/* test for type */
- type= GPU_NONE;
- for (i=1; i<=16; i++) {
+ type = GPU_NONE;
+ for (i = 1; i <= 16; i++) {
if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
- type= i;
+ type = i;
break;
}
}
@@ -182,8 +184,8 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
/* add parameter */
code = gpu_str_skip_token(code, NULL, 0);
code = gpu_str_skip_token(code, NULL, 0);
- function->paramqual[function->totparam]= qual;
- function->paramtype[function->totparam]= type;
+ function->paramqual[function->totparam] = qual;
+ function->paramtype[function->totparam] = type;
function->totparam++;
}
else {
@@ -220,7 +222,7 @@ static char *gpu_generate_function_prototyps(GHash *hash)
function = BLI_ghashIterator_getValue(ghi);
BLI_dynstr_appendf(ds, "void %s(", name);
- for (a=0; a<function->totparam; a++) {
+ for (a = 0; a < function->totparam; a++) {
if (function->paramqual[a] == FUNCTION_QUAL_OUT)
BLI_dynstr_append(ds, "out ");
else if (function->paramqual[a] == FUNCTION_QUAL_INOUT)
@@ -232,10 +234,11 @@ static char *gpu_generate_function_prototyps(GHash *hash)
BLI_dynstr_append(ds, "sampler2DShadow");
else
BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]);
-
- //BLI_dynstr_appendf(ds, " param%d", a);
-
- if (a != function->totparam-1)
+# if 0
+ BLI_dynstr_appendf(ds, " param%d", a);
+# endif
+
+ if (a != function->totparam - 1)
BLI_dynstr_append(ds, ", ");
}
BLI_dynstr_append(ds, ");\n");
@@ -267,7 +270,7 @@ void gpu_codegen_init(void)
void gpu_codegen_exit(void)
{
- extern Material defmaterial; // render module abuse...
+ extern Material defmaterial; /* render module abuse... */
if (defmaterial.gpumaterial.first)
GPU_material_free(&defmaterial.gpumaterial);
@@ -284,14 +287,16 @@ void gpu_codegen_exit(void)
glsl_material_library = NULL;
}
- /*if (FUNCTION_PROTOTYPES) {
+#if 0
+ if (FUNCTION_PROTOTYPES) {
MEM_freeN(FUNCTION_PROTOTYPES);
FUNCTION_PROTOTYPES = NULL;
- }*/
- /*if (FUNCTION_LIB) {
+ }
+ if (FUNCTION_LIB) {
GPU_shader_free(FUNCTION_LIB);
FUNCTION_LIB = NULL;
- }*/
+ }
+#endif
}
/* GLSL code generation */
@@ -306,18 +311,16 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
BLI_dynstr_append(ds, name);
}
else if (to == GPU_FLOAT) {
- if (from == GPU_VEC4)
- BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name);
- else if (from == GPU_VEC3)
- BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name);
+ if (from == GPU_VEC4 || from == GPU_VEC3)
+ BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
else if (from == GPU_VEC2)
BLI_dynstr_appendf(ds, "%s.r", name);
}
else if (to == GPU_VEC2) {
if (from == GPU_VEC4)
- BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name);
+ BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name);
else if (from == GPU_VEC3)
- BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name);
+ BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name);
else if (from == GPU_FLOAT)
BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
}
@@ -345,9 +348,9 @@ 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++) {
+ for (i = 0; i < type; i++) {
BLI_dynstr_appendf(ds, "%f", data[i]);
- if (i == type-1)
+ if (i == type - 1)
BLI_dynstr_append(ds, ")");
else
BLI_dynstr_append(ds, ", ");
@@ -412,11 +415,11 @@ static void codegen_set_unique_ids(ListBase *nodes)
GPUOutput *output;
int id = 1, texid = 0;
- bindhash= BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
- definehash= BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
+ bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
+ definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
/* set id for unique names of uniform variables */
input->id = id++;
input->bindtex = false;
@@ -463,7 +466,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
}
}
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
/* set id for unique names of tmp variables storing output */
output->id = id++;
}
@@ -480,8 +483,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
int builtins = 0;
/* print uniforms */
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
/* create exactly one sampler for each texture */
if (codegen_input_has_texture(input) && input->bindtex)
@@ -537,9 +540,9 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
GPUInput *input;
GPUOutput *output;
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
/* load pixels from textures */
- for (input=node->inputs.first; input; input=input->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_TEX_PIXEL) {
if (codegen_input_has_texture(input) && input->definetex) {
BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
@@ -550,7 +553,7 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
}
/* declare temporary variables for node output storage */
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
GPU_DATATYPE_STR[output->type], output->id);
}
@@ -564,10 +567,10 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
GPUInput *input;
GPUOutput *output;
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
BLI_dynstr_appendf(ds, "\t%s(", node->name);
- for (input=node->inputs.first; input; input=input->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_TEX) {
BLI_dynstr_appendf(ds, "samp%d", input->texid);
if (input->link)
@@ -602,7 +605,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
BLI_dynstr_append(ds, ", ");
}
- for (output=node->outputs.first; output; output=output->next) {
+ for (output = node->outputs.first; output; output = output->next) {
BLI_dynstr_appendf(ds, "tmp%d", output->id);
if (output->next)
BLI_dynstr_append(ds, ", ");
@@ -622,13 +625,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
char *code;
int builtins;
- /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/
+#if 0
+ BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
+#endif
codegen_set_unique_ids(nodes);
builtins = codegen_print_uniforms_functions(ds, nodes);
- //if (G.debug & G_DEBUG)
- // BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#if 0
+ if (G.debug & G_DEBUG)
+ BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#endif
BLI_dynstr_append(ds, "void main(void)\n");
BLI_dynstr_append(ds, "{\n");
@@ -645,7 +652,9 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
- //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+ if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
return code;
}
@@ -658,8 +667,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
char *code;
char *vertcode;
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
GPU_DATATYPE_STR[input->type], input->attribid);
@@ -685,8 +694,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_append(ds, vertcode);
- for (node=nodes->first; node; node=node->next)
- for (input=node->inputs.first; input; input=input->next)
+ for (node = nodes->first; node; node = node->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_TANGENT) { /* silly exception */
BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
@@ -714,16 +723,13 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_free(ds);
- //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+ if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
return code;
}
-int GPU_bicubic_bump_support(void)
-{
- return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
-}
-
void GPU_code_generate_glsl_lib(void)
{
DynStr *ds;
@@ -765,9 +771,9 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
GPU_shader_bind(shader);
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
z = 0;
- for (input=node->inputs.first; input; input=next, z++) {
+ for (input = node->inputs.first; input; input = next, z++) {
next = input->next;
/* attributes don't need to be bound, they already have
@@ -820,7 +826,7 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
GPU_shader_bind(shader);
/* now bind the textures */
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->ima)
input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap);
else if (input->prv)
@@ -844,10 +850,19 @@ void GPU_pass_update_uniforms(GPUPass *pass)
return;
/* pass dynamic inputs to opengl, others were removed */
- for (input=inputs->first; input; input=input->next)
- if (!(input->ima || input->tex || input->prv))
- GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
- input->dynamicvec);
+ for (input = inputs->first; input; input = input->next) {
+ if (!(input->ima || input->tex || input->prv)) {
+ if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) {
+ // The hardness is actually a short pointer, so we convert it here
+ float val = (float)(*(short*)input->dynamicvec);
+ GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val);
+ }
+ else {
+ GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
+ input->dynamicvec);
+ }
+ }
+ }
}
void GPU_pass_unbind(GPUPass *pass)
@@ -859,7 +874,7 @@ void GPU_pass_unbind(GPUPass *pass)
if (!shader)
return;
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->tex && input->bindtex)
GPU_texture_unbind(input->tex);
@@ -901,7 +916,7 @@ static GPUNode *GPU_node_begin(const char *name)
{
GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode");
- node->name= name;
+ node->name = name;
return node;
}
@@ -915,8 +930,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
if (link->output) {
outnode = link->output->node;
name = outnode->name;
+ input = outnode->inputs.first;
- if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
+ if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) &&
+ (input->type == type))
+ {
input = MEM_dupallocN(outnode->inputs.first);
input->type = type;
if (input->link)
@@ -970,7 +988,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->source = GPU_SOURCE_TEX;
input->textype = type;
- //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#if 0
+ input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#endif
input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
input->textarget = GL_TEXTURE_2D;
@@ -1009,9 +1029,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
memcpy(input->vec, link->ptr1, type*sizeof(float));
if (link->dynamic) {
- input->dynamicvec= link->ptr1;
- input->dynamictype= link->dynamictype;
- input->dynamicdata= link->ptr2;
+ input->dynamicvec = link->ptr1;
+ input->dynamictype = link->dynamictype;
+ input->dynamicdata = link->ptr2;
}
MEM_freeN(link);
}
@@ -1045,7 +1065,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
output->link->type = type;
output->link->output = output;
- /* note: the caller owns the reference to the linkfer, GPUOutput
+ /* note: the caller owns the reference to the link, GPUOutput
* merely points to it, and if the node is destroyed it will
* set that pointer to NULL */
}
@@ -1057,7 +1077,7 @@ static void gpu_inputs_free(ListBase *inputs)
{
GPUInput *input;
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->link)
gpu_node_link_free(input->link);
else if (input->tex && !input->dynamictex)
@@ -1073,7 +1093,7 @@ static void gpu_node_free(GPUNode *node)
gpu_inputs_free(&node->inputs);
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
if (output->link) {
output->link->output = NULL;
gpu_node_link_free(output->link);
@@ -1105,10 +1125,10 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
memset(attribs, 0, sizeof(*attribs));
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB) {
- for (a=0; a<attribs->totlayer; a++) {
+ for (a = 0; a < attribs->totlayer; a++) {
if (attribs->layer[a].type == input->attribtype &&
STREQ(attribs->layer[a].name, input->attribname))
{
@@ -1140,10 +1160,10 @@ static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
GPUNode *node;
GPUInput *input;
- *builtin= 0;
+ *builtin = 0;
- for (node=nodes->first; node; node=node->next)
- for (input=node->inputs.first; input; input=input->next)
+ for (node = nodes->first; node; node = node->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->source == GPU_SOURCE_BUILTIN)
*builtin |= input->builtin;
}
@@ -1154,8 +1174,8 @@ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
{
GPUNodeLink *link = GPU_node_link_create();
- link->attribtype= type;
- link->attribname= name;
+ link->attribtype = type;
+ link->attribname = name;
return link;
}
@@ -1164,8 +1184,8 @@ GPUNodeLink *GPU_uniform(float *num)
{
GPUNodeLink *link = GPU_node_link_create();
- link->ptr1= num;
- link->ptr2= NULL;
+ link->ptr1 = num;
+ link->ptr2 = NULL;
return link;
}
@@ -1174,9 +1194,9 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d
{
GPUNodeLink *link = GPU_node_link_create();
- link->ptr1= num;
- link->ptr2= data;
- link->dynamic= true;
+ link->ptr1 = num;
+ link->ptr2 = data;
+ link->dynamic = true;
link->dynamictype = dynamictype;
@@ -1199,8 +1219,8 @@ GPUNodeLink *GPU_image_preview(PreviewImage *prv)
{
GPUNodeLink *link = GPU_node_link_create();
- link->image= GPU_NODE_LINK_IMAGE_PREVIEW;
- link->ptr1= prv;
+ link->image = GPU_NODE_LINK_IMAGE_PREVIEW;
+ link->ptr1 = prv;
return link;
}
@@ -1212,7 +1232,7 @@ GPUNodeLink *GPU_texture(int size, float *pixels)
link->texture = true;
link->texturesize = size;
- link->ptr1= pixels;
+ link->ptr1 = pixels;
return link;
}
@@ -1264,13 +1284,13 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
node = GPU_node_begin(name);
va_start(params, name);
- for (i=0; i<function->totparam; i++) {
+ for (i = 0; i<function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
- linkptr= va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink**);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else {
- link= va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink*);
gpu_node_input_link(node, link, function->paramtype[i]);
}
}
@@ -1314,10 +1334,10 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
va_start(params, out);
- for (i=0; i<function->totparam; i++) {
+ for (i = 0; i<function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
- linkptr= va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink**);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else
@@ -1325,7 +1345,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
else {
if (totin == 0) {
- link= va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink*);
if (link->socket)
gpu_node_input_socket(node, link->socket);
else
@@ -1378,7 +1398,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
return;
node->tag = true;
- for (input=node->inputs.first; input; input=input->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->link)
gpu_nodes_tag(input->link);
}
@@ -1387,12 +1407,12 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
{
GPUNode *node, *next;
- for (node=nodes->first; node; node=node->next)
+ for (node = nodes->first; node; node = node->next)
node->tag = false;
gpu_nodes_tag(outlink);
- for (node=nodes->first; node; node=next) {
+ for (node = nodes->first; node; node = next) {
next = node->next;
if (!node->tag) {
@@ -1410,10 +1430,12 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
GPUPass *pass;
char *vertexcode, *fragmentcode;
- /*if (!FUNCTION_LIB) {
+#if 0
+ if (!FUNCTION_LIB) {
GPU_nodes_free(nodes);
return NULL;
- }*/
+ }
+#endif
/* prune unused nodes */
gpu_nodes_prune(nodes, outlink);
@@ -1424,7 +1446,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
/* generate code and compile with opengl */
fragmentcode = code_generate_fragment(nodes, outlink->output);
vertexcode = code_generate_vertex(nodes, type);
- shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
+ shader = GPU_shader_create(vertexcode, fragmentcode, NULL, glsl_material_library, NULL, 0, 0, 0);
/* failed? */
if (!shader) {
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index a6da5e018fd..c6ed2e3f837 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -43,7 +43,6 @@ struct GPUShader;
struct GPUOutput;
struct GPUNode;
struct GPUVertexAttribs;
-struct GPUFrameBuffer;
struct PreviewImage;
/* Pass Generation
@@ -113,9 +112,9 @@ typedef struct GPUOutput {
struct GPUOutput *next, *prev;
GPUNode *node;
- GPUType type; /* data type = length of vector/matrix */
- GPUNodeLink *link; /* output link */
- int id; /* unique id as created by code generator */
+ GPUType type; /* data type = length of vector/matrix */
+ GPUNodeLink *link; /* output link */
+ int id; /* unique id as created by code generator */
} GPUOutput;
typedef struct GPUInput {
@@ -123,35 +122,35 @@ typedef struct GPUInput {
GPUNode *node;
- GPUType type; /* datatype */
- GPUDataSource source; /* data source */
-
- int id; /* unique id as created by code generator */
- int texid; /* number for multitexture, starting from zero */
- int attribid; /* id for vertex attributes */
- bool bindtex; /* input is responsible for binding the texture? */
- bool definetex; /* input is responsible for defining the pixel? */
- int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
- GPUType textype; /* datatype */
-
- struct Image *ima; /* image */
- struct ImageUser *iuser;/* image user */
- struct PreviewImage *prv; /* preview images & icons */
- bool image_isdata; /* image does not contain color data */
- float *dynamicvec; /* vector data in case it is dynamic */
- GPUDynamicType dynamictype; /* origin of the dynamic uniform */
- void *dynamicdata; /* data source of the dynamic uniform */
- struct GPUTexture *tex; /* input texture, only set at runtime */
- int shaderloc; /* id from opengl */
- char shadername[32]; /* name in shader */
-
- float vec[16]; /* vector data */
+ GPUType type; /* datatype */
+ GPUDataSource source; /* data source */
+
+ int id; /* unique id as created by code generator */
+ int texid; /* number for multitexture, starting from zero */
+ int attribid; /* id for vertex attributes */
+ bool bindtex; /* input is responsible for binding the texture? */
+ bool definetex; /* input is responsible for defining the pixel? */
+ int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
+ GPUType textype; /* datatype */
+
+ struct Image *ima; /* image */
+ struct ImageUser *iuser; /* image user */
+ struct PreviewImage *prv; /* preview images & icons */
+ bool image_isdata; /* image does not contain color data */
+ float *dynamicvec; /* vector data in case it is dynamic */
+ GPUDynamicType dynamictype; /* origin of the dynamic uniform */
+ void *dynamicdata; /* data source of the dynamic uniform */
+ struct GPUTexture *tex; /* input texture, only set at runtime */
+ int shaderloc; /* id from opengl */
+ char shadername[32]; /* name in shader */
+
+ float vec[16]; /* vector data */
GPUNodeLink *link;
- bool dynamictex; /* dynamic? */
- CustomDataType attribtype; /* attribute type */
- char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
- int attribfirst; /* this is the first one that is bound */
- GPUBuiltin builtin; /* builtin uniform */
+ bool dynamictex; /* dynamic? */
+ CustomDataType attribtype; /* attribute type */
+ char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
+ int attribfirst; /* this is the first one that is bound */
+ GPUBuiltin builtin; /* builtin uniform */
GPUOpenGLBuiltin oglbuiltin; /* opengl built in varying */
} GPUInput;
@@ -170,8 +169,8 @@ struct GPUPass {
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
- struct GPUVertexAttribs *attribs, int *builtin,
- const GPUMatType type, const char *name);
+ struct GPUVertexAttribs *attribs, int *builtin,
+ const GPUMatType type, const char *name);
struct GPUShader *GPU_pass_shader(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 511167b775a..2bafee0fb52 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -50,7 +50,7 @@
#include "GPU_extensions.h"
#include "GPU_compositing.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -62,11 +62,20 @@ struct GPUFX {
* depth/color framebuffer. Could be extended later though */
GPUFrameBuffer *gbuffer;
+ /* dimensions of the gbuffer */
+ int gbuffer_dim[2];
+
/* texture bound to the first color attachment of the gbuffer */
GPUTexture *color_buffer;
/* second texture used for ping-pong compositing */
GPUTexture *color_buffer_sec;
+ /* texture bound to the depth attachment of the gbuffer */
+ GPUTexture *depth_buffer;
+ GPUTexture *depth_buffer_xray;
+
+ /* texture used for jittering for various effects */
+ GPUTexture *jitter_buffer;
/* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
int dof_downsampled_w;
@@ -80,26 +89,20 @@ struct GPUFX {
GPUTexture *dof_near_coc_final_buffer;
/* half size blur buffer */
- GPUTexture *dof_half_downsampled;
- /* high quality dof texture downsamplers. 6 levels means 64 pixels wide */
- GPUTexture *dof_nearfar_coc[6];
+ GPUTexture *dof_half_downsampled_near;
+ GPUTexture *dof_half_downsampled_far;
+ /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */
+ GPUTexture *dof_nearfar_coc;
GPUTexture *dof_near_blur;
GPUTexture *dof_far_blur;
- GPUTexture *dof_concentric_samples_tex;
-
- /* texture bound to the depth attachment of the gbuffer */
- GPUTexture *depth_buffer;
- GPUTexture *depth_buffer_xray;
- /* texture used for jittering for various effects */
- GPUTexture *jitter_buffer;
+ /* for high quality we use again a spiral texture with radius adapted */
+ bool dof_high_quality;
/* texture used for ssao */
- int ssao_sample_count;
- GPUTexture *ssao_concentric_samples_tex;
+ int ssao_sample_count_cache;
+ GPUTexture *ssao_spiral_samples_tex;
- /* dimensions of the gbuffer */
- int gbuffer_dim[2];
GPUFXSettings settings;
@@ -111,6 +114,8 @@ struct GPUFX {
/* we have a stencil, restore the previous state */
bool restore_stencil;
+
+ unsigned int vbuffer;
};
#if 0
@@ -174,6 +179,14 @@ GPUFX *GPU_fx_compositor_create(void)
{
GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor");
+ if (GLEW_ARB_vertex_buffer_object) {
+ glGenBuffersARB(1, &fx->vbuffer);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, 16 * sizeof(float), NULL, GL_STATIC_DRAW);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 8 * sizeof(float), fullscreencos);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
return fx;
}
@@ -192,16 +205,17 @@ static void cleanup_fx_dof_buffers(GPUFX *fx)
fx->dof_near_coc_final_buffer = NULL;
}
- if (fx->dof_half_downsampled) {
- GPU_texture_free(fx->dof_half_downsampled);
- fx->dof_half_downsampled = NULL;
+ if (fx->dof_half_downsampled_near) {
+ GPU_texture_free(fx->dof_half_downsampled_near);
+ fx->dof_half_downsampled_near = NULL;
}
- if (fx->dof_nearfar_coc[0]) {
- int i;
- for (i = 0; i < 6; i++) {
- GPU_texture_free(fx->dof_nearfar_coc[i]);
- fx->dof_nearfar_coc[i] = NULL;
- }
+ if (fx->dof_half_downsampled_far) {
+ GPU_texture_free(fx->dof_half_downsampled_far);
+ fx->dof_half_downsampled_far = NULL;
+ }
+ if (fx->dof_nearfar_coc) {
+ GPU_texture_free(fx->dof_nearfar_coc);
+ fx->dof_nearfar_coc = NULL;
}
if (fx->dof_near_blur) {
GPU_texture_free(fx->dof_near_blur);
@@ -211,10 +225,6 @@ static void cleanup_fx_dof_buffers(GPUFX *fx)
GPU_texture_free(fx->dof_far_blur);
fx->dof_far_blur = NULL;
}
- if (fx->dof_concentric_samples_tex) {
- GPU_texture_free(fx->dof_concentric_samples_tex);
- fx->dof_concentric_samples_tex = NULL;
- }
}
static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
@@ -245,9 +255,9 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
cleanup_fx_dof_buffers(fx);
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
- fx->ssao_concentric_samples_tex = NULL;
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
+ fx->ssao_spiral_samples_tex = NULL;
}
if (fx->jitter_buffer && do_fbo) {
@@ -265,6 +275,8 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
void GPU_fx_compositor_destroy(GPUFX *fx)
{
cleanup_fx_gl_data(fx, true);
+ if (GLEW_ARB_vertex_buffer_object)
+ glDeleteBuffersARB(1, &fx->vbuffer);
MEM_freeN(fx);
}
@@ -279,7 +291,7 @@ static GPUTexture * create_jitter_texture(void)
normalize_v2(jitter[i]);
}
- return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], NULL);
+ return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
}
@@ -356,54 +368,113 @@ bool GPU_fx_compositor_initialize_passes(
}
if (fx_flag & GPU_FX_FLAG_SSAO) {
- if (fx_settings->ssao->samples != fx->ssao_sample_count || !fx->ssao_concentric_samples_tex) {
+ if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) {
if (fx_settings->ssao->samples < 1)
fx_settings->ssao->samples = 1;
- fx->ssao_sample_count = fx_settings->ssao->samples;
+ fx->ssao_sample_count_cache = fx_settings->ssao->samples;
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
}
- fx->ssao_concentric_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
+ fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
}
}
else {
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
- fx->ssao_concentric_samples_tex = NULL;
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
+ fx->ssao_spiral_samples_tex = NULL;
}
}
/* create textures for dof effect */
if (fx_flag & GPU_FX_FLAG_DOF) {
- if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
+ bool dof_high_quality = (fx_settings->dof->high_quality != 0) &&
+ GPU_geometry_shader_support() && GPU_instanced_drawing_support();
+
+ /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
+ if (dof_high_quality != fx->dof_high_quality)
+ cleanup_fx_dof_buffers(fx);
+
+ if (dof_high_quality) {
+ fx->dof_downsampled_w = w / 2;
+ fx->dof_downsampled_h = h / 2;
+
+ if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur ||
+ !fx->dof_far_blur || !fx->dof_half_downsampled_far) {
+
+ if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+
+ if (!(fx->dof_near_blur = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+ if (!(fx->dof_far_blur = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ }
+ }
+ else {
fx->dof_downsampled_w = w / 4;
fx->dof_downsampled_h = h / 4;
- if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
+ if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
+
+ if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
}
}
+
+ fx->dof_high_quality = dof_high_quality;
}
else {
/* cleanup unnecessary buffers */
@@ -412,7 +483,7 @@ bool GPU_fx_compositor_initialize_passes(
/* we need to pass data between shader stages, allocate an extra color buffer */
if (num_passes > 1) {
- if(!fx->color_buffer_sec) {
+ if (!fx->color_buffer_sec) {
if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -431,13 +502,13 @@ bool GPU_fx_compositor_initialize_passes(
/* bind the buffers */
/* first depth buffer, because system assumes read/write buffers */
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
printf("%.256s\n", err_out);
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
printf("%.256s\n", err_out);
- if(!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
+ if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
printf("%.256s\n", err_out);
GPU_texture_bind_as_framebuffer(fx->color_buffer);
@@ -507,7 +578,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray)
GPU_framebuffer_texture_detach(fx->depth_buffer);
/* first depth buffer, because system assumes read/write buffers */
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out))
printf("%.256s\n", err_out);
}
@@ -529,8 +600,9 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* set up quad buffer */
- glVertexPointer(2, GL_FLOAT, 0, fullscreencos);
- glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glVertexPointer(2, GL_FLOAT, 0, NULL);
+ glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -544,14 +616,14 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
GPU_shader_bind(depth_resolve_shader);
GPU_texture_bind(fx->depth_buffer_xray, 0);
- GPU_depth_texture_mode(fx->depth_buffer_xray, false, true);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray);
/* draw */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* disable bindings */
- GPU_depth_texture_mode(fx->depth_buffer_xray, true, false);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, true, false);
GPU_texture_unbind(fx->depth_buffer_xray);
GPU_shader_unbind();
@@ -559,6 +631,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -572,6 +645,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
int numslots = 0;
float invproj[4][4];
int i;
+ float dfdyfac[2];
/* number of passes left. when there are no more passes, the result is passed to the frambuffer */
int passes_left = fx->num_passes;
/* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
@@ -584,6 +658,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
if (fx->effects == 0)
return false;
+ GPU_get_dfdy_factors(dfdyfac);
/* first, unbind the render-to-texture framebuffer */
GPU_framebuffer_texture_detach(fx->color_buffer);
GPU_framebuffer_texture_detach(fx->depth_buffer);
@@ -595,8 +670,9 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
target = fx->color_buffer_sec;
/* set up quad buffer */
- glVertexPointer(2, GL_FLOAT, 0, fullscreencos);
- glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glVertexPointer(2, GL_FLOAT, 0, NULL);
+ glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -641,12 +717,14 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform;
int ssao_jitter_uniform, ssao_concentric_tex;
float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
- float sample_params[4];
+ float sample_params[3];
- sample_params[0] = fx->ssao_sample_count;
+ sample_params[0] = fx->ssao_sample_count_cache;
/* multiplier so we tile the random texture on screen */
- sample_params[2] = fx->gbuffer_dim[0] / 64.0;
- sample_params[3] = fx->gbuffer_dim[1] / 64.0;
+ sample_params[1] = fx->gbuffer_dim[0] / 64.0;
+ sample_params[2] = fx->gbuffer_dim[1] / 64.0;
+
+ ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1];
ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params");
ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color");
@@ -662,20 +740,20 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params);
GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color);
GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 4, 1, sample_params);
+ GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 3, 1, sample_params);
GPU_texture_bind(src, numslots++);
GPU_shader_uniform_texture(ssao_shader, color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->jitter_buffer, numslots++);
GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer);
- GPU_texture_bind(fx->ssao_concentric_samples_tex, numslots++);
- GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_concentric_samples_tex);
+ GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++);
+ GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_spiral_samples_tex);
/* draw */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
@@ -684,10 +762,10 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* disable bindings */
GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->jitter_buffer);
- GPU_texture_unbind(fx->ssao_concentric_samples_tex);
+ GPU_texture_unbind(fx->ssao_spiral_samples_tex);
/* may not be attached, in that case this just returns */
if (target) {
@@ -709,7 +787,6 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* second pass, dof */
if (fx->effects & GPU_FX_FLAG_DOF) {
const GPUDOFSettings *fx_dof = fx->settings.dof;
- GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
float dof_params[4];
float scale = scene->unit.system ? scene->unit.scale_length : 1.0f;
/* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
@@ -722,248 +799,467 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length));
dof_params[1] = fx_dof->focus_distance / scale;
dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
- dof_params[3] = 0.0f;
-
- /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original
- * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based
- * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
- dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
- dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
- dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
- dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp);
- dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp);
-
- /* error occured, restore framebuffers and return */
- if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) {
- GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
- GPU_framebuffer_restore();
- return false;
- }
+ dof_params[3] = fx_dof->num_blades;
- /* pass first, first level of blur in low res buffer */
- {
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
+ if (fx->dof_high_quality) {
+ GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3;
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+ /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */
+ dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp);
+ dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp);
+ dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp);
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+ /* error occured, restore framebuffers and return */
+ if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) {
+ GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
+ GPU_framebuffer_restore();
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- GPU_shader_bind(dof_shader_pass1);
+ GPU_shader_unbind();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ return false;
+ }
- GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+ /* pass first, downsample the color buffer to near/far targets and calculate coc texture */
+ {
+ int depth_uniform, dof_uniform;
+ int viewvecs_uniform;
+ int invrendertargetdim_uniform, color_uniform;
+
+ float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
+
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+
+ GPU_shader_bind(dof_shader_pass1);
+
+ GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+
+ GPU_texture_bind(src, numslots++);
+ /* disable filtering for the texture so custom downsample can do the right thing */
+ GPU_texture_filter_mode(src, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, src);
+
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL);
+ /* binding takes care of setting the viewport to the downsampled size */
+ GPU_framebuffer_slots_bind(fx->gbuffer, 0);
+
+ GPU_framebuffer_check_valid(fx->gbuffer, NULL);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_filter_mode(src, false, true);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near);
+ GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far);
+ GPU_framebuffer_texture_detach(fx->dof_nearfar_coc);
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near);
+
+ numslots = 0;
+ }
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
+ /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according
+ * to circle of confusion */
+ {
+ int rendertargetdim_uniform, coc_uniform, color_uniform, select_uniform, dof_uniform;
+ int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h};
+ float selection[2] = {0.0f, 1.0f};
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+ rendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "rendertargetdim");
- /* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
- /* binding takes care of setting the viewport to the downsampled size */
- GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer);
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
+ coc_uniform = GPU_shader_get_uniform(dof_shader_pass2, "cocbuffer");
+ select_uniform = GPU_shader_get_uniform(dof_shader_pass2, "layerselection");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ GPU_shader_bind(dof_shader_pass2);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
- numslots = 0;
+ GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector_int(dof_shader_pass2, rendertargetdim_uniform, 2, 1, rendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+
+ GPU_texture_bind(fx->dof_nearfar_coc, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, coc_uniform, fx->dof_nearfar_coc);
+
+ GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
+ GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_far);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false);
+
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL);
+ GPU_texture_bind_as_framebuffer(fx->dof_far_blur);
+
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ /* have to clear the buffer unfortunately */
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
+ glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
+
+ GPU_texture_unbind(fx->dof_half_downsampled_far);
+ GPU_framebuffer_texture_detach(fx->dof_far_blur);
+
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_near);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false);
+
+ selection[0] = 1.0f;
+ selection[1] = 0.0f;
+
+ GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL);
+ /* have to clear the buffer unfortunately */
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
+ glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
+
+ /* disable bindings */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+
+ GPU_framebuffer_texture_detach(fx->dof_near_blur);
+
+ GPU_texture_unbind(fx->dof_half_downsampled_near);
+ GPU_texture_unbind(fx->dof_nearfar_coc);
+
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur);
+ }
+
+ /* third pass, accumulate the near/far blur fields */
+ {
+ int invrendertargetdim_uniform, near_uniform, color_uniform;
+ int dof_uniform, far_uniform, viewvecs_uniform, depth_uniform;
+
+ float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
+
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass3, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass3, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
+ far_uniform = GPU_shader_get_uniform(dof_shader_pass3, "farbuffer");
+ near_uniform = GPU_shader_get_uniform(dof_shader_pass3, "nearbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass3, "viewvecs");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass3, "depthbuffer");
+
+ GPU_shader_bind(dof_shader_pass3);
+
+ GPU_shader_uniform_vector(dof_shader_pass3, dof_uniform, 4, 1, dof_params);
+
+ GPU_shader_uniform_vector(dof_shader_pass3, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass3, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_texture_bind(fx->dof_near_blur, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_uniform, fx->dof_near_blur);
+ GPU_texture_filter_mode(fx->dof_near_blur, false, true);
+
+ GPU_texture_bind(fx->dof_far_blur, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, far_uniform, fx->dof_far_blur);
+ GPU_texture_filter_mode(fx->dof_far_blur, false, true);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass3, depth_uniform, fx->depth_buffer);
+
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, color_uniform, src);
+
+ /* if this is the last pass, prepare for rendering on the frambuffer */
+ gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_blur);
+ GPU_texture_unbind(fx->dof_far_blur);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ /* may not be attached, in that case this just returns */
+ if (target) {
+ GPU_framebuffer_texture_detach(target);
+ if (ofs) {
+ GPU_offscreen_bind(ofs, false);
+ }
+ else {
+ GPU_framebuffer_restore();
+ }
+ }
+
+ numslots = 0;
+ }
}
+ else {
+ GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
+
+ /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original
+ * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based
+ * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
+ dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
+ dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
+ dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
+ dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp);
+ dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp);
+
+ /* error occured, restore framebuffers and return */
+ if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) {
+ GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
+ GPU_framebuffer_restore();
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ GPU_shader_unbind();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ return false;
+ }
- /* second pass, gaussian blur the downsampled image */
- {
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
- float tmp = invrendertargetdim[0];
- invrendertargetdim[0] = 0.0f;
+ /* pass first, first level of blur in low res buffer */
+ {
+ int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
+ int viewvecs_uniform;
- dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
+ float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
- /* Blurring vertically */
- GPU_shader_bind(dof_shader_pass2);
+ GPU_shader_bind(dof_shader_pass1);
- GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer);
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
- /* use final buffer as a temp here */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
+ /* binding takes care of setting the viewport to the downsampled size */
+ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer);
- /* Drawing quad */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
- /* *unbind/detach */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
+ numslots = 0;
+ }
- /* Blurring horizontally */
- invrendertargetdim[0] = tmp;
- invrendertargetdim[1] = 0.0f;
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ /* second pass, gaussian blur the downsampled image */
+ {
+ int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
+ int viewvecs_uniform;
+ float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ float tmp = invrendertargetdim[0];
+ invrendertargetdim[0] = 0.0f;
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer);
+ dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs");
- /* *unbind/detach */
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ /* Blurring vertically */
+ GPU_shader_bind(dof_shader_pass2);
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
+ GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]);
- dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer);
- numslots = 0;
- }
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
- /* third pass, calculate near coc */
- {
- int near_coc_downsampled, near_coc_blurred;
+ /* use final buffer as a temp here */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
- near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
+ /* Drawing quad */
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- GPU_shader_bind(dof_shader_pass3);
+ /* *unbind/detach */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer);
+ /* Blurring horizontally */
+ invrendertargetdim[0] = tmp;
+ invrendertargetdim[1] = 0.0f;
+ GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer);
+ GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
+ /* *unbind/detach */
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_final_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
- numslots = 0;
- }
+ dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
- /* fourth pass blur final coc once to eliminate discontinuities */
- {
- int near_coc_downsampled;
- int invrendertargetdim_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ numslots = 0;
+ }
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
+ /* third pass, calculate near coc */
+ {
+ int near_coc_downsampled, near_coc_blurred;
- GPU_shader_bind(dof_shader_pass4);
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
+ near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer);
- GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_bind(dof_shader_pass3);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
+ GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer);
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
- numslots = 0;
- }
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
- /* final pass, merge blurred layers according to final calculated coc */
- {
- int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform;
- int invrendertargetdim_uniform, viewvecs_uniform;
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+ /* unbinding here restores the size to the original */
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
- medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer");
- high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer");
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim");
- original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs");
+ numslots = 0;
+ }
- GPU_shader_bind(dof_shader_pass5);
+ /* fourth pass blur final coc once to eliminate discontinuities */
+ {
+ int near_coc_downsampled;
+ int invrendertargetdim_uniform;
+ float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
- GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]);
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src);
+ GPU_shader_bind(dof_shader_pass4);
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
+ GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer);
+ GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_final_buffer);
- /* if this is the last pass, prepare for rendering on the frambuffer */
- gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+ /* unbinding here restores the size to the original */
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
- GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ numslots = 0;
+ }
- /* may not be attached, in that case this just returns */
- if (target) {
- GPU_framebuffer_texture_detach(target);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else {
- GPU_framebuffer_restore();
+ /* final pass, merge blurred layers according to final calculated coc */
+ {
+ int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform;
+ int invrendertargetdim_uniform, viewvecs_uniform;
+ float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+
+ medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer");
+ high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim");
+ original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs");
+
+ GPU_shader_bind(dof_shader_pass5);
+
+ GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src);
+
+ GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
+
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer);
+
+ /* if this is the last pass, prepare for rendering on the frambuffer */
+ gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ /* may not be attached, in that case this just returns */
+ if (target) {
+ GPU_framebuffer_texture_detach(target);
+ if (ofs) {
+ GPU_offscreen_bind(ofs, false);
+ }
+ else {
+ GPU_framebuffer_restore();
+ }
}
- }
- SWAP(GPUTexture *, target, src);
- numslots = 0;
+ SWAP(GPUTexture *, target, src);
+ numslots = 0;
+ }
}
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
GPU_shader_unbind();
@@ -976,6 +1272,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof)
fx_dof->focal_length = 1.0f;
fx_dof->focus_distance = 1.0f;
fx_dof->sensor = 1.0f;
+ fx_dof->num_blades = 6;
}
void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index 627aa41dca5..21d7eb4370b 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -45,7 +45,7 @@
static const char* gpu_gl_error_symbol(GLenum err)
{
- switch(err) {
+ switch (err) {
CASE_CODE_RETURN_STR(GL_NO_ERROR)
CASE_CODE_RETURN_STR(GL_INVALID_ENUM)
CASE_CODE_RETURN_STR(GL_INVALID_VALUE)
@@ -109,7 +109,7 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str)
const char* gpuErrorString(GLenum err)
{
- switch(err) {
+ switch (err) {
case GL_NO_ERROR:
return "No Error";
@@ -191,6 +191,7 @@ void gpu_debug_init(void)
#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY)
if (GLEW_VERSION_4_3) {
+ glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_STRING_MARKER(sizeof(success), success);
@@ -199,23 +200,11 @@ void gpu_debug_init(void)
#endif
if (GLEW_KHR_debug) {
-#ifndef GLEW_NO_ES
- if (MX_profile_es20)
- {
- glDebugMessageCallbackKHR(gpu_debug_proc, mxGetCurrentContext());
- glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_STRING_MARKER(sizeof(success), success);
- }
- else
-#endif
- {
#ifndef GLEW_ES_ONLY
glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_STRING_MARKER(sizeof(success), success);
#endif
- }
-
return;
}
@@ -256,19 +245,9 @@ void gpu_debug_exit(void)
#endif
if (GLEW_KHR_debug) {
-#ifndef GLEW_NO_ES
- if (MX_profile_es20)
- {
- glDebugMessageCallbackKHR(NULL, NULL);
- }
- else
-#endif
- {
#ifndef GLEW_ES_ONLY
- glDebugMessageCallback(NULL, NULL);
+ glDebugMessageCallback(NULL, NULL);
#endif
- }
-
return;
}
@@ -302,19 +281,9 @@ void gpu_string_marker(size_t length, const char *buf)
#endif
if (GLEW_KHR_debug) {
-#ifndef GLEW_NO_ES
- if (MX_profile_es20)
- {
- glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, GL_DEBUG_TYPE_MARKER_KHR, 0, GL_DEBUG_SEVERITY_NOTIFICATION_KHR, length, buf);
- }
- else
-#endif
- {
#ifndef GLEW_ES_ONLY
- glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
+ glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
#endif
- }
-
return;
}
@@ -356,6 +325,7 @@ void gpu_assert_no_gl_errors(const char* file, int line, const char* str)
GLboolean gl_ok = gpu_report_gl_errors(file, line, str);
BLI_assert(gl_ok);
+ (void) gl_ok;
}
}
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 3ed7253d309..a24067fc381 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -88,7 +88,7 @@ extern Material defmaterial; /* from material.c */
static void gpu_mcol(unsigned int ucol)
{
/* mcol order is swapped */
- const char *cp= (char *)&ucol;
+ const char *cp = (char *)&ucol;
glColor3ub(cp[3], cp[2], cp[1]);
}
@@ -96,7 +96,7 @@ void GPU_render_text(MTFace *tface, int mode,
const char *textstr, int textlen, unsigned int *col,
float *v1, float *v2, float *v3, float *v4, int glattrib)
{
- if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) {
+ if ((mode & GEMAT_TEXT) && (textlen > 0) && tface->tpage) {
Image* ima = (Image *)tface->tpage;
ImBuf *first_ibuf;
const size_t textlen_st = textlen;
@@ -105,7 +105,7 @@ void GPU_render_text(MTFace *tface, int mode,
float advance_tab;
/* multiline */
- float line_start= 0.0f, line_height;
+ float line_start = 0.0f, line_height;
if (v4)
line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
@@ -117,7 +117,7 @@ void GPU_render_text(MTFace *tface, int mode,
/* color has been set */
if (tface->mode & TF_OBCOL)
- col= NULL;
+ col = NULL;
else if (!col)
glColor3f(1.0f, 1.0f, 1.0f);
@@ -128,23 +128,23 @@ void GPU_render_text(MTFace *tface, int mode,
matrixGlyph(first_ibuf, ' ', &centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
- advance_tab= advance * 4; /* tab width could also be an option */
+ advance_tab = advance * 4; /* tab width could also be an option */
for (index = 0; index < textlen_st; ) {
unsigned int character;
float uv[4][2];
- // lets calculate offset stuff
+ /* lets calculate offset stuff */
character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
- if (character=='\n') {
- glTranslatef(line_start, -line_height, 0.0);
+ if (character == '\n') {
+ glTranslatef(line_start, -line_height, 0.0f);
line_start = 0.0f;
continue;
}
- else if (character=='\t') {
- glTranslatef(advance_tab, 0.0, 0.0);
+ else if (character == '\t') {
+ glTranslatef(advance_tab, 0.0f, 0.0f);
line_start -= advance_tab; /* so we can go back to the start of the line */
continue;
@@ -154,8 +154,8 @@ void GPU_render_text(MTFace *tface, int mode,
character = '?';
}
- // space starts at offset 1
- // character = character - ' ' + 1;
+ /* space starts at offset 1 */
+ /* character = character - ' ' + 1; */
matrixGlyph(first_ibuf, character, & centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
@@ -193,7 +193,7 @@ void GPU_render_text(MTFace *tface, int mode,
}
glEnd();
- glTranslatef(advance, 0.0, 0.0);
+ glTranslatef(advance, 0.0f, 0.0f);
line_start -= advance; /* so we can go back to the start of the line */
}
glPopMatrix();
@@ -239,14 +239,18 @@ static struct GPUTextureState {
int curtileYRep, tileYRep;
Image *ima, *curima;
- int domipmap, linearmipmap;
- int texpaint; /* store this so that new images created while texture painting won't be set to mipmapped */
+ /* also controls min/mag filtering */
+ bool domipmap;
+ /* only use when 'domipmap' is set */
+ bool linearmipmap;
+ /* store this so that new images created while texture painting won't be set to mipmapped */
+ bool texpaint;
int alphablend;
float anisotropic;
int gpu_mipmap;
MTFace *lasttface;
-} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.f, 0, NULL};
+} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
/* Mipmap settings */
@@ -281,49 +285,53 @@ static void gpu_generate_mipmap(GLenum target)
glDisable(target);
}
-void GPU_set_mipmap(int mipmap)
+void GPU_set_mipmap(bool mipmap)
{
- if (GTS.domipmap != (mipmap != 0)) {
+ if (GTS.domipmap != mipmap) {
GPU_free_images();
- GTS.domipmap = mipmap != 0;
+ GTS.domipmap = mipmap;
}
}
-void GPU_set_linear_mipmap(int linear)
+void GPU_set_linear_mipmap(bool linear)
{
- if (GTS.linearmipmap != (linear != 0)) {
- GPU_free_images();
- GTS.linearmipmap = linear != 0;
+ if (GTS.linearmipmap != linear) {
+ GTS.linearmipmap = linear;
}
}
-int GPU_get_mipmap(void)
+bool GPU_get_mipmap(void)
{
return GTS.domipmap && !GTS.texpaint;
}
-int GPU_get_linear_mipmap(void)
+bool GPU_get_linear_mipmap(void)
{
return GTS.linearmipmap;
}
-static GLenum gpu_get_mipmap_filter(int mag)
+static GLenum gpu_get_mipmap_filter(bool mag)
{
/* linearmipmap is off by default *when mipmapping is off,
* use unfiltered display */
if (mag) {
- if (GTS.linearmipmap || GTS.domipmap)
+ if (GTS.domipmap)
return GL_LINEAR;
else
return GL_NEAREST;
}
else {
- if (GTS.linearmipmap)
- return GL_LINEAR_MIPMAP_LINEAR;
- else if (GTS.domipmap)
- return GL_LINEAR_MIPMAP_NEAREST;
- else
+ if (GTS.domipmap) {
+ if (GTS.linearmipmap) {
+ return GL_LINEAR_MIPMAP_LINEAR;
+ }
+ else {
+ return GL_LINEAR_MIPMAP_NEAREST;
+ }
+ }
+ else {
return GL_NEAREST;
+ }
}
}
@@ -353,41 +361,41 @@ static void gpu_make_repbind(Image *ima)
ImBuf *ibuf;
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf==NULL)
+ if (ibuf == NULL)
return;
if (ima->repbind) {
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
- ima->repbind= NULL;
+ ima->repbind = NULL;
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
- ima->totbind= ima->xrep*ima->yrep;
+ ima->totbind = ima->xrep*ima->yrep;
if (ima->totbind>1)
- ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
+ ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind");
BKE_image_release_ibuf(ima, ibuf, NULL);
}
void GPU_clear_tpage(bool force)
{
- if (GTS.lasttface==NULL && !force)
+ if (GTS.lasttface == NULL && !force)
return;
- GTS.lasttface= NULL;
- GTS.curtile= 0;
- GTS.curima= NULL;
- if (GTS.curtilemode!=0) {
+ GTS.lasttface = NULL;
+ GTS.curtile = 0;
+ GTS.curima = NULL;
+ if (GTS.curtilemode != 0) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
- GTS.curtilemode= 0;
- GTS.curtileXRep=0;
- GTS.curtileYRep=0;
- GTS.alphablend= -1;
+ GTS.curtilemode = 0;
+ GTS.curtileXRep = 0;
+ GTS.curtileYRep = 0;
+ GTS.alphablend = -1;
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
@@ -403,7 +411,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
glDisable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- else if (alphablend==GPU_BLEND_ADD) {
+ else if (alphablend == GPU_BLEND_ADD) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDisable(GL_ALPHA_TEST);
@@ -429,7 +437,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
glAlphaFunc(GL_GREATER, U.glalphaclip);
}
}
- else if (alphablend==GPU_BLEND_CLIP) {
+ else if (alphablend == GPU_BLEND_CLIP) {
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
@@ -443,7 +451,7 @@ static void gpu_verify_alpha_blend(int alphablend)
return;
gpu_set_alpha_blend(alphablend);
- GTS.alphablend= alphablend;
+ GTS.alphablend = alphablend;
}
static void gpu_verify_reflection(Image *ima)
@@ -467,9 +475,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
{
ImBuf *ibuf = NULL;
unsigned int *bind = NULL;
- int rectw, recth, tpx=0, tpy=0, y;
- unsigned int *tilerect= NULL, *rect= NULL;
- float *ftilerect= NULL, *frect = NULL;
+ int rectw, recth, tpx = 0, tpy = 0, y;
+ unsigned int *tilerect = NULL, *rect = NULL;
+ float *ftilerect = NULL, *frect = NULL;
float *srgb_frect = NULL;
short texwindx, texwindy, texwinsx, texwinsy;
/* flag to determine whether high resolution format is used */
@@ -477,15 +485,15 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
/* initialize tile mode and number of repeats */
GTS.ima = ima;
- GTS.tilemode= (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM)));
+ GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM)));
GTS.tileXRep = 0;
GTS.tileYRep = 0;
/* setting current tile according to frame */
if (ima && (ima->tpageflag & IMA_TWINANIM))
- GTS.tile= ima->lastframe;
+ GTS.tile = ima->lastframe;
else
- GTS.tile= tftile;
+ GTS.tile = tftile;
GTS.tile = MAX2(0, GTS.tile);
@@ -503,26 +511,26 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
}
/* if tiling mode or repeat changed, change texture matrix to fit */
- if (GTS.tilemode!=GTS.curtilemode || GTS.curtileXRep!=GTS.tileXRep ||
+ if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
GTS.curtileYRep != GTS.tileYRep)
{
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if (ima && (ima->tpageflag & IMA_TILES))
- glScalef(ima->xrep, ima->yrep, 1.0);
+ glScalef(ima->xrep, ima->yrep, 1.0f);
glMatrixMode(GL_MODELVIEW);
}
/* check if we have a valid image */
- if (ima==NULL || ima->ok==0)
+ if (ima == NULL || ima->ok == 0)
return 0;
/* check if we have a valid image buffer */
- ibuf= BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf==NULL)
+ if (ibuf == NULL)
return 0;
if (ibuf->rect_float) {
@@ -552,59 +560,58 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (GTS.tilemode) {
/* tiled mode */
- if (ima->repbind==NULL) gpu_make_repbind(ima);
- if (GTS.tile>=ima->totbind) GTS.tile= 0;
+ if (ima->repbind == NULL) gpu_make_repbind(ima);
+ if (GTS.tile >= ima->totbind) GTS.tile = 0;
/* this happens when you change repeat buttons */
- if (ima->repbind) bind= &ima->repbind[GTS.tile];
- else bind= &ima->bindcode;
+ if (ima->repbind) bind = &ima->repbind[GTS.tile];
+ else bind = &ima->bindcode;
- if (*bind==0) {
-
- texwindx= ibuf->x/ima->xrep;
- texwindy= ibuf->y/ima->yrep;
+ if (*bind == 0) {
+ texwindx = ibuf->x / ima->xrep;
+ texwindy = ibuf->y / ima->yrep;
- if (GTS.tile>=ima->xrep*ima->yrep)
- GTS.tile= ima->xrep*ima->yrep-1;
+ if (GTS.tile >= ima->xrep * ima->yrep)
+ GTS.tile = ima->xrep * ima->yrep - 1;
- texwinsy= GTS.tile / ima->xrep;
- texwinsx= GTS.tile - texwinsy*ima->xrep;
+ texwinsy = GTS.tile / ima->xrep;
+ texwinsx = GTS.tile - texwinsy * ima->xrep;
- texwinsx*= texwindx;
- texwinsy*= texwindy;
+ texwinsx *= texwindx;
+ texwinsy *= texwindy;
- tpx= texwindx;
- tpy= texwindy;
+ tpx = texwindx;
+ tpy = texwindy;
if (use_high_bit_depth) {
if (do_color_management) {
- srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor");
+ srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
- frect= srgb_frect + texwinsy*ibuf->x + texwinsx;
+ frect = srgb_frect + texwinsy*ibuf->x + texwinsx;
}
else
- frect= ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
+ frect = ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
}
else
- rect= ibuf->rect + texwinsy*ibuf->x + texwinsx;
+ rect = ibuf->rect + texwinsy*ibuf->x + texwinsx;
}
}
else {
/* regular image mode */
bind= &ima->bindcode;
- if (*bind==0) {
- tpx= ibuf->x;
- tpy= ibuf->y;
- rect= ibuf->rect;
+ if (*bind == 0) {
+ tpx = ibuf->x;
+ tpy = ibuf->y;
+ rect = ibuf->rect;
if (use_high_bit_depth) {
if (do_color_management) {
- frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor");
+ frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
@@ -613,7 +620,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
}
else
- frect= ibuf->rect_float;
+ frect = ibuf->rect_float;
}
}
}
@@ -633,30 +640,30 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (use_high_bit_depth) {
float *frectrow, *ftilerectrow;
- ftilerect= MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
+ ftilerect = MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
- for (y=0; y<recth; y++) {
- frectrow= &frect[y*ibuf->x];
- ftilerectrow= &ftilerect[y*rectw];
+ for (y = 0; y < recth; y++) {
+ frectrow = &frect[y * ibuf->x];
+ ftilerectrow = &ftilerect[y * rectw];
- memcpy(ftilerectrow, frectrow, tpx*sizeof(*frectrow));
+ memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow));
}
- frect= ftilerect;
+ frect = ftilerect;
}
else {
unsigned int *rectrow, *tilerectrow;
- tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
+ tilerect = MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
- for (y=0; y<recth; y++) {
- rectrow= &rect[y*ibuf->x];
- tilerectrow= &tilerect[y*rectw];
+ for (y = 0; y < recth; y++) {
+ rectrow = &rect[y * ibuf->x];
+ tilerectrow = &tilerect[y * rectw];
- memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
+ memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
}
- rect= tilerect;
+ rect = tilerect;
}
}
@@ -723,43 +730,56 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int
glGenTextures(1, (GLuint *)bind);
glBindTexture(GL_TEXTURE_2D, *bind);
- if (!(GPU_get_mipmap() && mipmap)) {
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
}
- else {
- if (GTS.gpu_mipmap) {
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+
+ if (GPU_get_mipmap() && mipmap) {
+ if (GTS.gpu_mipmap) {
gpu_generate_mipmap(GL_TEXTURE_2D);
}
else {
- if (use_high_bit_depth)
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect);
- else
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ int i;
+
+ if (!ibuf) {
+ if (use_high_bit_depth) {
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ }
+ else {
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ }
+ }
+
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 1; i < ibuf->miptot; i++) {
+ ImBuf *mip = ibuf->mipmap[i - 1];
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ else
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ }
+ else {
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
+ }
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
if (ima)
ima->tpageflag |= IMA_MIPMAP_COMPLETE;
}
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
@@ -812,7 +832,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) {
+ for (i = 0; i < ibuf->dds_data.nummipmaps && (width||height); ++i) {
if (width == 0)
width = 1;
if (height == 0)
@@ -829,7 +849,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
}
/* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
return true;
#else
@@ -875,21 +895,21 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
Image *ima;
/* check if we need to clear the state */
- if (tface==NULL) {
+ if (tface == NULL) {
GPU_clear_tpage(false);
return 0;
}
- ima= tface->tpage;
- GTS.lasttface= tface;
+ ima = tface->tpage;
+ GTS.lasttface = tface;
gpu_verify_alpha_blend(alphablend);
gpu_verify_reflection(ima);
if (GPU_verify_image(ima, NULL, tface->tile, 1, mipmap, false)) {
- GTS.curtile= GTS.tile;
- GTS.curima= GTS.ima;
- GTS.curtilemode= GTS.tilemode;
+ GTS.curtile = GTS.tile;
+ GTS.curima = GTS.ima;
+ GTS.curtilemode = GTS.tilemode;
GTS.curtileXRep = GTS.tileXRep;
GTS.curtileYRep = GTS.tileYRep;
@@ -898,9 +918,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
else {
glDisable(GL_TEXTURE_2D);
- GTS.curtile= 0;
- GTS.curima= NULL;
- GTS.curtilemode= 0;
+ GTS.curtile = 0;
+ GTS.curima = NULL;
+ GTS.curtilemode = 0;
GTS.curtileXRep = 0;
GTS.curtileYRep = 0;
@@ -919,9 +939,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
* temporary disabling/enabling mipmapping on all images for quick texture
* updates with glTexSubImage2D. images that didn't change don't have to be
* re-uploaded to OpenGL */
-void GPU_paint_set_mipmap(int mipmap)
+void GPU_paint_set_mipmap(bool mipmap)
{
- Image* ima;
+ Image *ima;
if (!GTS.domipmap)
return;
@@ -929,7 +949,7 @@ void GPU_paint_set_mipmap(int mipmap)
GTS.texpaint = !mipmap;
if (mipmap) {
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->bindcode) {
if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
@@ -945,7 +965,7 @@ void GPU_paint_set_mipmap(int mipmap)
}
else {
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->bindcode) {
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1028,11 +1048,11 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
return false;
}
-void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
+void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ima->repbind || (GPU_get_mipmap() && !GTS.gpu_mipmap) || !ima->bindcode || !ibuf ||
(w == 0) || (h == 0))
@@ -1058,8 +1078,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
}
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
- GL_FLOAT, buffer);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
MEM_freeN(buffer);
@@ -1114,16 +1133,16 @@ void GPU_update_images_framechange(void)
{
Image *ima;
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep*ima->yrep)
- ima->twend= ima->xrep*ima->yrep-1;
+ if (ima->twend >= ima->xrep * ima->yrep)
+ ima->twend = ima->xrep * ima->yrep - 1;
/* check: is bindcode not in the array? free. (to do) */
ima->lastframe++;
if (ima->lastframe > ima->twend)
- ima->lastframe= ima->twsta;
+ ima->lastframe = ima->twsta;
}
}
}
@@ -1131,33 +1150,33 @@ void GPU_update_images_framechange(void)
int GPU_update_image_time(Image *ima, double time)
{
int inc = 0;
- float diff;
+ float diff;
int newframe;
if (!ima)
return 0;
- if (ima->lastupdate<0)
+ if (ima->lastupdate < 0)
ima->lastupdate = 0;
if (ima->lastupdate > (float)time)
- ima->lastupdate=(float)time;
+ ima->lastupdate = (float)time;
if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
+ if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
/* check: is the bindcode not in the array? Then free. (still to do) */
diff = (float)((float)time - ima->lastupdate);
- inc = (int)(diff*(float)ima->animspeed);
+ inc = (int)(diff * (float)ima->animspeed);
- ima->lastupdate+=((float)inc/(float)ima->animspeed);
+ ima->lastupdate += ((float)inc / (float)ima->animspeed);
- newframe = ima->lastframe+inc;
+ newframe = ima->lastframe + inc;
if (newframe > (int)ima->twend) {
- if (ima->twend-ima->twsta != 0)
- newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta);
+ if (ima->twend - ima->twsta != 0)
+ newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta);
else
newframe = ima->twsta;
}
@@ -1194,7 +1213,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
if (!sds->tex && !highres) {
/* rgba texture for color + density */
if (smoke_has_colors(sds->fluid)) {
- float *data = MEM_callocN(sizeof(float)*sds->total_cells*4, "smokeColorTexture");
+ float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
smoke_get_rgba(sds->fluid, data, 0);
sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
MEM_freeN(data);
@@ -1208,7 +1227,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
else if (!sds->tex && highres) {
/* rgba texture for color + density */
if (smoke_turbulence_has_colors(sds->wt)) {
- float *data = MEM_callocN(sizeof(float)*smoke_turbulence_get_cells(sds->wt)*4, "smokeColorTexture");
+ float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
smoke_turbulence_get_rgba(sds->wt, data, 0);
sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
MEM_freeN(data);
@@ -1224,9 +1243,9 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
}
#else // WITH_SMOKE
(void)highres;
- smd->domain->tex= NULL;
- smd->domain->tex_flame= NULL;
- smd->domain->tex_shadow= NULL;
+ smd->domain->tex = NULL;
+ smd->domain->tex_flame = NULL;
+ smd->domain->tex_shadow = NULL;
#endif // WITH_SMOKE
}
@@ -1250,7 +1269,7 @@ void GPU_free_unused_buffers(void)
BLI_lock_thread(LOCK_OPENGL);
/* images */
- for (node=image_free_queue; node; node=node->next) {
+ for (node = image_free_queue; node; node = node->next) {
ima = node->link;
/* check in case it was freed in the meantime */
@@ -1277,13 +1296,13 @@ void GPU_free_image(Image *ima)
/* free regular image binding */
if (ima->bindcode) {
glDeleteTextures(1, (GLuint *)&ima->bindcode);
- ima->bindcode= 0;
+ ima->bindcode = 0;
}
/* free glsl image binding */
if (ima->gputexture) {
GPU_texture_free(ima->gputexture);
- ima->gputexture= NULL;
+ ima->gputexture = NULL;
}
/* free repeated image binding */
@@ -1291,7 +1310,7 @@ void GPU_free_image(Image *ima)
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
- ima->repbind= NULL;
+ ima->repbind = NULL;
}
ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE|IMA_GLBIND_IS_DATA);
@@ -1299,20 +1318,20 @@ void GPU_free_image(Image *ima)
void GPU_free_images(void)
{
- Image* ima;
+ Image *ima;
if (G.main)
- for (ima=G.main->image.first; ima; ima=ima->id.next)
+ for (ima = G.main->image.first; ima; ima = ima->id.next)
GPU_free_image(ima);
}
/* same as above but only free animated images */
void GPU_free_images_anim(void)
{
- Image* ima;
+ Image *ima;
if (G.main)
- for (ima=G.main->image.first; ima; ima=ima->id.next)
+ for (ima = G.main->image.first; ima; ima = ima->id.next)
if (BKE_image_is_animated(ima))
GPU_free_image(ima);
}
@@ -1358,7 +1377,7 @@ void GPU_free_images_old(void)
/* OpenGL Materials */
-#define FIXEDMAT 8
+#define FIXEDMAT 8
/* OpenGL state caching for materials */
@@ -1401,21 +1420,21 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat,
{
if (bmat->mode & MA_SHLESS) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3]= 1.0;
+ smat->diff[3] = 1.0;
if (gamma)
linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
zero_v4(smat->spec);
- smat->hard= 0;
+ smat->hard = 0;
}
else if (new_shading_nodes) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3]= 1.0;
+ smat->diff[3] = 1.0;
copy_v3_v3(smat->spec, &bmat->specr);
smat->spec[3] = 1.0;
- smat->hard= CLAMPIS(bmat->har, 0, 128);
+ smat->hard = CLAMPIS(bmat->har, 0, 128);
if (dimdown) {
mul_v3_fl(smat->diff, 0.8f);
@@ -1429,13 +1448,13 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat,
}
else {
mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit);
- smat->diff[3]= 1.0; /* caller may set this to bmat->alpha */
+ smat->diff[3] = 1.0; /* caller may set this to bmat->alpha */
if (bmat->shade_flag & MA_OBCOLOR)
mul_v3_v3(smat->diff, ob->col);
mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
- smat->spec[3]= 1.0; /* always 1 */
+ smat->spec[3] = 1.0; /* always 1 */
smat->hard= CLAMPIS(bmat->har, 0, 128);
if (gamma) {
@@ -1487,10 +1506,10 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.gob = ob;
GMS.gscene = scene;
GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */
- GMS.glay= (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
+ GMS.glay = (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
GMS.gscenelock = (v3d->scenelock != 0);
- GMS.gviewmat= rv3d->viewmat;
- GMS.gviewinv= rv3d->viewinv;
+ GMS.gviewmat = rv3d->viewmat;
+ GMS.gviewinv = rv3d->viewinv;
GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
/* alpha pass setup. there's various cases to handle here:
@@ -1504,14 +1523,14 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
*do_alpha_after = false;
if (GMS.totmat > FIXEDMAT) {
- GMS.matbuf= MEM_callocN(sizeof(GPUMaterialFixed)*GMS.totmat, "GMS.matbuf");
- GMS.gmatbuf= MEM_callocN(sizeof(*GMS.gmatbuf)*GMS.totmat, "GMS.matbuf");
- GMS.alphablend= MEM_callocN(sizeof(*GMS.alphablend)*GMS.totmat, "GMS.matbuf");
+ GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
+ GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
+ GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf");
}
else {
- GMS.matbuf= GMS.matbuf_fixed;
- GMS.gmatbuf= GMS.gmatbuf_fixed;
- GMS.alphablend= GMS.alphablend_fixed;
+ GMS.matbuf = GMS.matbuf_fixed;
+ GMS.gmatbuf = GMS.gmatbuf_fixed;
+ GMS.alphablend = GMS.alphablend_fixed;
}
/* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */
@@ -1522,38 +1541,38 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
/* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
- GMS.alphablend[0]= GPU_BLEND_SOLID;
+ GMS.alphablend[0] = GPU_BLEND_SOLID;
}
else {
/* no materials assigned? */
- if (ob->totcol==0) {
+ if (ob->totcol == 0) {
gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
/* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
if (glsl) {
- GMS.gmatbuf[0]= &defmaterial;
+ GMS.gmatbuf[0] = &defmaterial;
GPU_material_from_blender(GMS.gscene, &defmaterial);
}
- GMS.alphablend[0]= GPU_BLEND_SOLID;
+ GMS.alphablend[0] = GPU_BLEND_SOLID;
}
/* setup materials */
- for (a=1; a<=ob->totcol; a++) {
+ for (a = 1; a <= ob->totcol; a++) {
/* find a suitable material */
- ma= give_current_material(ob, a);
- if (!glsl && !new_shading_nodes) ma= gpu_active_node_material(ma);
- if (ma==NULL) ma= &defmaterial;
+ ma = give_current_material(ob, a);
+ if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma);
+ if (ma == NULL) ma = &defmaterial;
/* create glsl material if requested */
- gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL;
+ gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma): NULL;
if (gpumat) {
/* do glsl only if creating it succeed, else fallback */
- GMS.gmatbuf[a]= ma;
+ GMS.gmatbuf[a] = ma;
alphablend = GPU_material_alpha_blend(gpumat, ob->col);
}
else {
@@ -1561,11 +1580,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false);
if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) {
- GMS.matbuf[a].diff[3]= ma->alpha;
+ GMS.matbuf[a].diff[3] = ma->alpha;
alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
}
else {
- GMS.matbuf[a].diff[3]= 1.0f;
+ GMS.matbuf[a].diff[3] = 1.0f;
alphablend = GPU_BLEND_SOLID;
}
}
@@ -1576,10 +1595,10 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
*do_alpha_after = true;
- GMS.alphablend[a]= alphablend;
+ GMS.alphablend[a] = alphablend;
}
}
-
+
/* let's start with a clean state */
GPU_disable_material();
}
@@ -1597,10 +1616,10 @@ int GPU_enable_material(int nr, void *attribs)
memset(&GMS, 0, sizeof(GMS));
mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
- diff[3]= 1.0;
+ diff[3] = 1.0;
mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec);
- spec[3]= 1.0;
+ spec[3] = 1.0;
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
@@ -1610,21 +1629,21 @@ int GPU_enable_material(int nr, void *attribs)
}
/* prevent index to use un-initialized array items */
- if (nr>=GMS.totmat)
- nr= 0;
+ if (nr >= GMS.totmat)
+ nr = 0;
if (gattribs)
memset(gattribs, 0, sizeof(*gattribs));
/* keep current material */
- if (nr==GMS.lastmatnr)
+ if (nr == GMS.lastmatnr)
return GMS.lastretval;
/* unbind glsl material */
if (GMS.gboundmat) {
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
- GMS.gboundmat= NULL;
+ GMS.gboundmat = NULL;
}
/* draw materials with alpha in alpha pass */
@@ -1654,7 +1673,7 @@ int GPU_enable_material(int nr, void *attribs)
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale);
- GMS.gboundmat= mat;
+ GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and
* we are already drawing in an alpha pass */
@@ -1671,7 +1690,7 @@ int GPU_enable_material(int nr, void *attribs)
}
if (GMS.use_matcaps)
- glColor3f(1.0, 1.0, 1.0f);
+ glColor3f(1.0f, 1.0f, 1.0f);
}
else {
/* or do fixed function opengl material */
@@ -1703,8 +1722,8 @@ int GPU_get_material_alpha_blend(void)
void GPU_disable_material(void)
{
- GMS.lastmatnr= -1;
- GMS.lastretval= 1;
+ GMS.lastmatnr = -1;
+ GMS.lastretval = 1;
if (GMS.gboundmat) {
if (GMS.backface_culling)
@@ -1712,7 +1731,7 @@ void GPU_disable_material(void)
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
- GMS.gboundmat= NULL;
+ GMS.gboundmat = NULL;
}
GPU_set_material_alpha_blend(GPU_BLEND_SOLID);
@@ -1749,9 +1768,9 @@ void GPU_end_object_materials(void)
MEM_freeN(GMS.alphablend);
}
- GMS.matbuf= NULL;
- GMS.gmatbuf= NULL;
- GMS.alphablend= NULL;
+ GMS.matbuf = NULL;
+ GMS.gmatbuf = NULL;
+ GMS.alphablend = NULL;
/* resetting the texture matrix after the scaling needed for tiled textures */
if (GTS.tilemode) {
@@ -1769,57 +1788,57 @@ int GPU_default_lights(void)
int a, count = 0;
/* initialize */
- if (U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0) {
- U.light[0].flag= 1;
- U.light[0].vec[0]= -0.3; U.light[0].vec[1]= 0.3; U.light[0].vec[2]= 0.9;
- U.light[0].col[0]= 0.8; U.light[0].col[1]= 0.8; U.light[0].col[2]= 0.8;
- U.light[0].spec[0]= 0.5; U.light[0].spec[1]= 0.5; U.light[0].spec[2]= 0.5;
- U.light[0].spec[3]= 1.0;
+ if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) {
+ U.light[0].flag = 1;
+ U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9;
+ U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
+ U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
+ U.light[0].spec[3] = 1.0;
- U.light[1].flag= 0;
- U.light[1].vec[0]= 0.5; U.light[1].vec[1]= 0.5; U.light[1].vec[2]= 0.1;
- U.light[1].col[0]= 0.4; U.light[1].col[1]= 0.4; U.light[1].col[2]= 0.8;
- U.light[1].spec[0]= 0.3; U.light[1].spec[1]= 0.3; U.light[1].spec[2]= 0.5;
- U.light[1].spec[3]= 1.0;
+ U.light[1].flag = 0;
+ U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
+ U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
+ U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
+ U.light[1].spec[3] = 1.0;
- U.light[2].flag= 0;
- U.light[2].vec[0]= 0.3; U.light[2].vec[1]= -0.3; U.light[2].vec[2]= -0.2;
- U.light[2].col[0]= 0.8; U.light[2].col[1]= 0.5; U.light[2].col[2]= 0.4;
- U.light[2].spec[0]= 0.5; U.light[2].spec[1]= 0.4; U.light[2].spec[2]= 0.3;
- U.light[2].spec[3]= 1.0;
+ U.light[2].flag = 0;
+ U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
+ U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
+ U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3;
+ U.light[2].spec[3] = 1.0;
}
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
- for (a=0; a<8; a++) {
- if (a<3) {
+ for (a = 0; a < 8; a++) {
+ if (a < 3) {
if (U.light[a].flag) {
- glEnable(GL_LIGHT0+a);
+ glEnable(GL_LIGHT0 + a);
normalize_v3_v3(position, U.light[a].vec);
- position[3]= 0.0f;
+ position[3] = 0.0f;
- glLightfv(GL_LIGHT0+a, GL_POSITION, position);
- glLightfv(GL_LIGHT0+a, GL_DIFFUSE, U.light[a].col);
- glLightfv(GL_LIGHT0+a, GL_SPECULAR, U.light[a].spec);
+ glLightfv(GL_LIGHT0 + a, GL_POSITION, position);
+ glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, U.light[a].col);
+ glLightfv(GL_LIGHT0 + a, GL_SPECULAR, U.light[a].spec);
count++;
}
else {
- glDisable(GL_LIGHT0+a);
+ glDisable(GL_LIGHT0 + a);
- glLightfv(GL_LIGHT0+a, GL_POSITION, zero);
- glLightfv(GL_LIGHT0+a, GL_DIFFUSE, zero);
- glLightfv(GL_LIGHT0+a, GL_SPECULAR, zero);
+ glLightfv(GL_LIGHT0 + a, GL_POSITION, zero);
+ glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, zero);
+ glLightfv(GL_LIGHT0 + a, GL_SPECULAR, zero);
}
- // clear stuff from other opengl lamp usage
- glLightf(GL_LIGHT0+a, GL_SPOT_CUTOFF, 180.0);
- glLightf(GL_LIGHT0+a, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+a, GL_LINEAR_ATTENUATION, 0.0);
+ /* clear stuff from other opengl lamp usage */
+ glLightf(GL_LIGHT0 + a, GL_SPOT_CUTOFF, 180.0);
+ glLightf(GL_LIGHT0 + a, GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf(GL_LIGHT0 + a, GL_LINEAR_ATTENUATION, 0.0);
}
else
- glDisable(GL_LIGHT0+a);
+ glDisable(GL_LIGHT0 + a);
}
glDisable(GL_LIGHTING);
@@ -1837,68 +1856,68 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
float position[4], direction[4], energy[4];
/* disable all lights */
- for (count=0; count<8; count++)
- glDisable(GL_LIGHT0+count);
+ for (count = 0; count < 8; count++)
+ glDisable(GL_LIGHT0 + count);
- /* view direction for specular is not compute correct by default in
+ /* view direction for specular is not computed correct by default in
* opengl, so we set the settings ourselfs */
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (ortho)? GL_FALSE: GL_TRUE);
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, ortho ? GL_FALSE : GL_TRUE);
- count= 0;
-
- for (base=scene->base.first; base; base=base->next) {
- if (base->object->type!=OB_LAMP)
+ count = 0;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (base->object->type != OB_LAMP)
continue;
if (!(base->lay & lay) || !(base->lay & ob->lay))
continue;
- la= base->object->data;
+ la = base->object->data;
/* setup lamp transform */
glPushMatrix();
glLoadMatrixf((float *)viewmat);
- if (la->type==LA_SUN) {
+ if (la->type == LA_SUN) {
/* sun lamp */
copy_v3_v3(direction, base->object->obmat[2]);
- direction[3]= 0.0;
+ direction[3] = 0.0;
glLightfv(GL_LIGHT0+count, GL_POSITION, direction);
}
else {
/* other lamps with attenuation */
copy_v3_v3(position, base->object->obmat[3]);
- position[3]= 1.0f;
+ position[3] = 1.0f;
glLightfv(GL_LIGHT0+count, GL_POSITION, position);
glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
- glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
+ glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1 / la->dist);
+ glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2 / (la->dist * la->dist));
- if (la->type==LA_SPOT) {
+ if (la->type == LA_SPOT) {
/* spot lamp */
negate_v3_v3(direction, base->object->obmat[2]);
- glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, direction);
- glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f));
- glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0f*la->spotblend);
+ glLightfv(GL_LIGHT0 + count, GL_SPOT_DIRECTION, direction);
+ glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f));
+ glLightf(GL_LIGHT0 + count, GL_SPOT_EXPONENT, 128.0f * la->spotblend);
}
else
- glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
+ glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, 180.0);
}
/* setup energy */
mul_v3_v3fl(energy, &la->r, la->energy);
- energy[3]= 1.0;
+ energy[3] = 1.0;
- glLightfv(GL_LIGHT0+count, GL_DIFFUSE, energy);
- glLightfv(GL_LIGHT0+count, GL_SPECULAR, energy);
- glEnable(GL_LIGHT0+count);
+ glLightfv(GL_LIGHT0 + count, GL_DIFFUSE, energy);
+ glLightfv(GL_LIGHT0 + count, GL_SPECULAR, energy);
+ glEnable(GL_LIGHT0 + count);
glPopMatrix();
count++;
- if (count==8)
+ if (count == 8)
break;
}
@@ -1944,8 +1963,8 @@ void GPU_state_init(void)
float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
int a, x, y;
- GLubyte pat[32*32];
- const GLubyte *patc= pat;
+ GLubyte pat[32 * 32];
+ const GLubyte *patc = pat;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
@@ -1990,14 +2009,14 @@ void GPU_state_init(void)
glPixelTransferi(GL_DEPTH_SCALE, 1);
glDepthRange(0.0, 1.0);
- a= 0;
- for (x=0; x<32; x++) {
- for (y=0; y<4; y++) {
- if ( (x) & 1) pat[a++]= 0x88;
- else pat[a++]= 0x22;
+ a = 0;
+ for (x = 0; x < 32; x++) {
+ for (y = 0; y < 4; y++) {
+ if (x & 1) pat[a++] = 0x88;
+ else pat[a++] = 0x22;
}
}
-
+
glPolygonStipple(patc);
glMatrixMode(GL_TEXTURE);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 63f0bc37acf..b757aff4bdb 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BKE_global.h"
@@ -61,6 +62,7 @@
#endif
#define MAX_DEFINE_LENGTH 72
+#define MAX_EXT_DEFINE_LENGTH 280
/* Extensions support */
@@ -75,6 +77,8 @@
*/
/* Non-generated shaders */
+extern char datatoc_gpu_program_smoke_frag_glsl[];
+extern char datatoc_gpu_program_smoke_color_frag_glsl[];
extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
@@ -83,12 +87,17 @@ extern char datatoc_gpu_shader_fx_vert_glsl[];
extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
extern char datatoc_gpu_shader_fx_lib_glsl[];
typedef struct GPUShaders {
GPUShader *vsm_store;
GPUShader *sep_gaussian_blur;
+ GPUProgram *smoke;
+ GPUProgram *smoke_colored;
/* cache for shader fx. Those can exist in combinations so store them here */
GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
} GPUShaders;
@@ -109,6 +118,9 @@ static struct GPUGlobal {
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
GPUTexture *invalid_tex_2D;
GPUTexture *invalid_tex_3D;
+ float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
+ calculate dfdy in shader differently when drawing to an offscreen buffer. First
+ number is factor on screen and second is off-screen */
} GG = {1, 0};
/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
@@ -123,7 +135,7 @@ struct GPUFrameBuffer {
/* GPU Types */
-int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
+bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
{
return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
}
@@ -140,10 +152,15 @@ int GPU_max_texture_size(void)
return GG.maxtexsize;
}
+void GPU_get_dfdy_factors(float fac[2])
+{
+ copy_v2_v2(fac, GG.dfdyfactors);
+}
+
void gpu_extensions_init(void)
{
GLint r, g, b;
- const char *vendor, *renderer;
+ const char *vendor, *renderer, *version;
/* glewIsSupported("GL_VERSION_2_0") */
@@ -160,10 +177,11 @@ void gpu_extensions_init(void)
glGetIntegerv(GL_RED_BITS, &r);
glGetIntegerv(GL_GREEN_BITS, &g);
glGetIntegerv(GL_BLUE_BITS, &b);
- GG.colordepth = r+g+b; /* assumes same depth for RGB */
+ GG.colordepth = r + g + b; /* assumes same depth for RGB */
vendor = (const char *)glGetString(GL_VENDOR);
renderer = (const char *)glGetString(GL_RENDERER);
+ version = (const char *)glGetString(GL_VERSION);
if (strstr(vendor, "ATI")) {
GG.device = GPU_DEVICE_ATI;
@@ -240,6 +258,27 @@ void gpu_extensions_init(void)
#endif
+ /* df/dy calculation factors, those are dependent on driver */
+ if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = -1.0;
+ }
+ else if (GG.device == GPU_DEVICE_INTEL && GG.os == GPU_OS_WIN &&
+ (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3186") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3165") ||
+ strstr(version, "3.1.0 - Build 9.17.10.3347") ||
+ strstr(version, "3.1.0 - Build 9.17.10.4101")))
+ {
+ GG.dfdyfactors[0] = -1.0;
+ GG.dfdyfactors[1] = 1.0;
+ }
+ else {
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = 1.0;
+ }
+
+
GPU_invalid_tex_init();
GPU_simple_shaders_init();
}
@@ -250,29 +289,44 @@ void gpu_extensions_exit(void)
GPU_invalid_tex_free();
}
-int GPU_glsl_support(void)
+bool GPU_glsl_support(void)
{
return !GG.extdisabled && GG.glslsupport;
}
-int GPU_non_power_of_two_support(void)
+bool GPU_non_power_of_two_support(void)
{
if (GG.npotdisabled)
- return 0;
+ return false;
return GLEW_ARB_texture_non_power_of_two;
}
-int GPU_vertex_buffer_support(void)
+bool GPU_vertex_buffer_support(void)
{
return GLEW_ARB_vertex_buffer_object || GLEW_VERSION_1_5;
}
-int GPU_display_list_support(void)
+bool GPU_display_list_support(void)
{
return !GG.dlistsdisabled;
}
+bool GPU_bicubic_bump_support(void)
+{
+ return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
+}
+
+bool GPU_geometry_shader_support(void)
+{
+ return GLEW_EXT_geometry_shader4 || GLEW_VERSION_3_2;
+}
+
+bool GPU_instanced_drawing_support(void)
+{
+ return GLEW_ARB_draw_instanced;
+}
+
int GPU_color_depth(void)
{
return GG.colordepth;
@@ -280,34 +334,34 @@ int GPU_color_depth(void)
static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
{
- const char *err= "unknown";
+ const char *err = "unknown";
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_INVALID_OPERATION:
- err= "Invalid operation";
+ err = "Invalid operation";
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- err= "Incomplete attachment";
+ err = "Incomplete attachment";
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- err= "Unsupported framebuffer format";
+ err = "Unsupported framebuffer format";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
- err= "Missing attachment";
+ err = "Missing attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- err= "Attached images must have same dimensions";
+ err = "Attached images must have same dimensions";
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
- err= "Attached images must have same format";
+ err = "Attached images must have same format";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
- err= "Missing draw buffer";
+ err = "Missing draw buffer";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
- err= "Missing read buffer";
+ err = "Missing read buffer";
break;
}
@@ -324,29 +378,28 @@ static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
/* GPUTexture */
struct GPUTexture {
- int w, h; /* width/height */
- int number; /* number for multitexture binding */
- int refcount; /* reference count */
- GLenum target; /* GL_TEXTURE_* */
- GLuint bindcode; /* opengl identifier for texture */
- int fromblender; /* we got the texture from Blender */
-
- GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
- int fb_attachment; /* slot the texture is attached to */
- int depth; /* is a depth texture? */
+ int w, h; /* width/height */
+ int number; /* number for multitexture binding */
+ int refcount; /* reference count */
+ GLenum target; /* GL_TEXTURE_* */
+ GLuint bindcode; /* opengl identifier for texture */
+ int fromblender; /* we got the texture from Blender */
+
+ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
+ int fb_attachment; /* slot the texture is attached to */
+ int depth; /* is a depth texture? if 3D how deep? */
};
-static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
+static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
{
unsigned char *pixels, *p;
- const float *fp;
- int a, len;
+ const float *fp = fpixels;
+ const int len = 4 * length;
+ int a;
- len = 4*length;
- fp = fpixels;
- p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
+ p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
- for (a=0; a<len; a++, p++, fp++)
+ for (a = 0; a < len; a++, p++, fp++)
*p = FTOCHAR((*fp));
return pixels;
@@ -354,7 +407,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
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");
+ void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
if (target == GL_TEXTURE_1D)
glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
@@ -365,7 +418,7 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i
}
static GPUTexture *GPU_texture_create_nD(
- int w, int h, int n, float *fpixels, int depth, GPUHDRType hdr_type, int components,
+ int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components,
char err_out[256])
{
GPUTexture *tex;
@@ -507,12 +560,13 @@ static GPUTexture *GPU_texture_create_nD(
}
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels)
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
{
GPUTexture *tex;
GLenum type, format, internalformat;
void *pixels = NULL;
- float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ int r_width;
+ bool rescale = false;
if (!GLEW_VERSION_1_2)
return NULL;
@@ -555,35 +609,90 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *
internalformat = GL_INTENSITY;
}
- //if (fpixels)
- // pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
+ /* 3D textures are quite heavy, test if it's possible to create them first */
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+
+ while (r_width == 0) {
+ rescale = true;
+ tex->w /= 2;
+ tex->h /= 2;
+ tex->depth /= 2;
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ }
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ /* really unlikely to happen but keep this just in case */
+ tex->w = max_ii(tex->w, 1);
+ tex->h = max_ii(tex->h, 1);
+ tex->depth = max_ii(tex->depth, 1);
+
+#if 0
+ if (fpixels)
+ pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
+#endif
GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
- if (fpixels) {
- if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
- /* clear first to avoid unitialized pixels */
- float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
- glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
- MEM_freeN(zero);
+ /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
+ * for gooseberry */
+ if (rescale && fpixels) {
+ unsigned int i, j, k;
+ unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
+ float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d");
+
+ GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+
+ for (k = 0; k < tex->depth; k++) {
+ for (j = 0; j < tex->h; j++) {
+ for (i = 0; i < tex->w; i++) {
+ /* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */
+ float xb = i * xf;
+ float yb = j * yf;
+ float zb = k * zf;
+ unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
+ unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+
+ if (channels == 4) {
+ tex3d[offset * 4] = fpixels[offset_orig * 4];
+ tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
+ tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
+ tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
+ }
+ else
+ tex3d[offset] = fpixels[offset_orig];
+ }
+ }
}
- glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
- GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
+
+ MEM_freeN(tex3d);
+ }
+ else {
+ if (fpixels) {
+ if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
+ /* clear first to avoid unitialized pixels */
+ float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, GL_INTENSITY, GL_FLOAT, zero);
+ glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
+ MEM_freeN(zero);
+ }
+ else {
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
+ }
+
+ GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
+ }
}
- glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_TEXTURE_BORDER_COLOR");
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_LINEAR");
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_CLAMP_TO_BORDER");
if (pixels)
MEM_freeN(pixels);
@@ -664,7 +773,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
tex->refcount = 1;
tex->target = GL_TEXTURE_2D;
- prv->gputexture[0]= tex;
+ prv->gputexture[0] = tex;
if (!glIsTexture(tex->bindcode)) {
GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
@@ -684,7 +793,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
}
-GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out);
@@ -694,7 +803,7 @@ GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
return tex;
}
-GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, GPUHDRType hdr, char err_out[256])
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out);
@@ -732,14 +841,16 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
return tex;
}
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
if (tex) {
/* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ if (repeat) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -749,7 +860,7 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char e
return tex;
}
-GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
@@ -767,7 +878,7 @@ GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[
void GPU_invalid_tex_init(void)
{
- float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
+ const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
@@ -859,7 +970,7 @@ void GPU_texture_unbind(GPUTexture *tex)
GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
}
-void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
{
GLenum arbnumber;
@@ -868,11 +979,6 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
return;
}
- if (!tex->depth) {
- fprintf(stderr, "Not a depth texture.");
- return;
- }
-
if (tex->number == -1)
return;
@@ -880,10 +986,13 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
if (tex->number != 0) glActiveTextureARB(arbnumber);
- if (compare)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+
+ if (tex->depth) {
+ if (compare)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ }
if (use_filter) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -920,22 +1029,22 @@ void GPU_texture_ref(GPUTexture *tex)
tex->refcount++;
}
-int GPU_texture_target(GPUTexture *tex)
+int GPU_texture_target(const GPUTexture *tex)
{
return tex->target;
}
-int GPU_texture_opengl_width(GPUTexture *tex)
+int GPU_texture_opengl_width(const GPUTexture *tex)
{
return tex->w;
}
-int GPU_texture_opengl_height(GPUTexture *tex)
+int GPU_texture_opengl_height(const GPUTexture *tex)
{
return tex->h;
}
-int GPU_texture_opengl_bindcode(GPUTexture *tex)
+int GPU_texture_opengl_bindcode(const GPUTexture *tex)
{
return tex->bindcode;
}
@@ -954,7 +1063,7 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
if (!GLEW_EXT_framebuffer_object)
return NULL;
- fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
+ fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
glGenFramebuffersEXT(1, &fb->object);
if (!fb->object) {
@@ -1047,8 +1156,7 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex)
attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment;
}
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
- tex->target, 0, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0);
tex->fb = NULL;
tex->fb_attachment = -1;
@@ -1098,7 +1206,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
return;
}
- for (i = 0 ; i < 4; i++) {
+ for (i = 0; i < 4; i++) {
if (fb->colortex[i]) {
attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
numslots++;
@@ -1288,7 +1396,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
{
GPUOffScreen *ofs;
- ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
+ ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
ofs->fb = GPU_framebuffer_create();
if (!ofs->fb) {
@@ -1364,12 +1472,12 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glReadPixels(0, 0, ofs->color->w, ofs->color->h, GL_RGBA, type, pixels);
}
-int GPU_offscreen_width(GPUOffScreen *ofs)
+int GPU_offscreen_width(const GPUOffScreen *ofs)
{
return ofs->color->w;
}
-int GPU_offscreen_height(GPUOffScreen *ofs)
+int GPU_offscreen_height(const GPUOffScreen *ofs)
{
return ofs->color->h;
}
@@ -1377,23 +1485,30 @@ int GPU_offscreen_height(GPUOffScreen *ofs)
/* GPUShader */
struct GPUShader {
- GLhandleARB object; /* handle for full shader */
- GLhandleARB vertex; /* handle for vertex shader */
- GLhandleARB fragment; /* handle for fragment shader */
- GLhandleARB lib; /* handle for libment shader */
- int totattrib; /* total number of attributes */
- int uniforms; /* required uniforms */
+ GLhandleARB object; /* handle for full shader */
+ GLhandleARB vertex; /* handle for vertex shader */
+ GLhandleARB fragment; /* handle for fragment shader */
+ GLhandleARB geometry; /* handle for geometry shader */
+ GLhandleARB lib; /* handle for libment shader */
+ int totattrib; /* total number of attributes */
+ int uniforms; /* required uniforms */
+};
+
+struct GPUProgram {
+ GPUProgramType type;
+ GLuint prog;
};
-static void shader_print_errors(const char *task, char *log, const char **code, int totcode)
+
+static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
{
int i;
+ int line = 1;
fprintf(stderr, "GPUShader: %s error:\n", task);
for (i = 0; i < totcode; i++) {
const char *c, *pos, *end = code[i] + strlen(code[i]);
- int line = 1;
if ((G.debug & G_DEBUG)) {
fprintf(stderr, "===== shader string %d ====\n", i + 1);
@@ -1401,8 +1516,8 @@ static void shader_print_errors(const char *task, char *log, const char **code,
c = code[i];
while ((c < end) && (pos = strchr(c, '\n'))) {
fprintf(stderr, "%2d ", line);
- fwrite(c, (pos+1)-c, 1, stderr);
- c = pos+1;
+ fwrite(c, (pos + 1) - c, 1, stderr);
+ c = pos + 1;
line++;
}
@@ -1426,13 +1541,19 @@ static const char *gpu_shader_version(void)
}
-static const char *gpu_shader_standard_extensions(void)
+static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
{
- /* need this extensions for high quality bump mapping */
+ /* need this extension for high quality bump mapping */
if (GPU_bicubic_bump_support())
- return "#extension GL_ARB_texture_query_lod: enable\n";
+ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
- return "";
+ if (GPU_geometry_shader_support())
+ strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
+
+ if (GPU_instanced_drawing_support()) {
+ strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
+ strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -1453,15 +1574,80 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
return;
}
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines)
+void GPU_program_bind(GPUProgram *program)
+{
+ glEnable(program->type);
+ glBindProgramARB(program->type, program->prog);
+}
+
+void GPU_program_unbind(GPUProgram *program)
+{
+ glDisable(program->type);
+ glBindProgramARB(program->type, 0);
+}
+
+
+GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code)
+{
+ GPUProgram *program;
+ GLint error_pos, is_native;
+
+ if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT))
+ return NULL;
+
+ program = MEM_callocN(sizeof(GPUProgram), "GPUProgram");
+
+ switch (type) {
+ case GPU_PROGRAM_TYPE_FRAGMENT:
+ program->type = GL_FRAGMENT_PROGRAM_ARB;
+ break;
+ }
+
+ /* create the object and set its code string */
+ glGenProgramsARB(1, &program->prog);
+ glBindProgramARB(program->type, program->prog);
+
+ glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code);
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native);
+ if ((error_pos == -1) && (is_native == 1)) {
+ return program;
+ }
+ else {
+ /* glGetError is set before that, clear it */
+ while (glGetError() != GL_NO_ERROR)
+ ;
+ shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1);
+ MEM_freeN(program);
+ }
+
+ return NULL;
+}
+
+void GPU_program_free(GPUProgram *program)
+{
+ glDeleteProgramsARB(1, &program->prog);
+ MEM_freeN(program);
+}
+
+void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w)
+{
+ glProgramLocalParameter4fARB(program->type, location, x, y, z, w);
+}
+
+
+
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number)
{
GLint status;
GLcharARB log[5000];
GLsizei length = 0;
GPUShader *shader;
char standard_defines[MAX_DEFINE_LENGTH] = "";
+ char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
- if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
+ if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support()))
return NULL;
shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
@@ -1470,11 +1656,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
if (fragcode)
shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ if (geocode)
+ shader->geometry = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT);
+
shader->object = glCreateProgramObjectARB();
if (!shader->object ||
(vertexcode && !shader->vertex) ||
- (fragcode && !shader->fragment))
+ (fragcode && !shader->fragment) ||
+ (geocode && !shader->geometry))
{
fprintf(stderr, "GPUShader, object creation failed.\n");
GPU_shader_free(shader);
@@ -1482,6 +1672,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
gpu_shader_standard_defines(standard_defines);
+ gpu_shader_standard_extensions(standard_extensions);
if (vertexcode) {
const char *source[5];
@@ -1489,11 +1680,11 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
int num_source = 0;
source[num_source++] = gpu_shader_version();
- source[num_source++] = gpu_shader_standard_extensions();
+ source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
- if (vertexcode) source[num_source++] = vertexcode;
+ source[num_source++] = vertexcode;
glAttachObjectARB(shader->object, shader->vertex);
glShaderSourceARB(shader->vertex, num_source, source, NULL);
@@ -1515,12 +1706,12 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
int num_source = 0;
source[num_source++] = gpu_shader_version();
- source[num_source++] = gpu_shader_standard_extensions();
+ source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
if (libcode) source[num_source++] = libcode;
- if (fragcode) source[num_source++] = fragcode;
+ source[num_source++] = fragcode;
glAttachObjectARB(shader->object, shader->fragment);
glShaderSourceARB(shader->fragment, num_source, source, NULL);
@@ -1537,6 +1728,35 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
}
+ if (geocode) {
+ const char *source[6];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (defines) source[num_source++] = defines;
+ source[num_source++] = geocode;
+
+ glAttachObjectARB(shader->object, shader->geometry);
+ glShaderSourceARB(shader->geometry, num_source, source, NULL);
+
+ glCompileShaderARB(shader->geometry);
+ glGetObjectParameterivARB(shader->geometry, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+
+ if (!status) {
+ glGetInfoLogARB(shader->geometry, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
+ }
+
+
#if 0
if (lib && lib->lib)
glAttachObjectARB(shader->object, lib->lib);
@@ -1549,6 +1769,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
if (fragcode) shader_print_errors("linking", log, &fragcode, 1);
else if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
else if (libcode) shader_print_errors("linking", log, &libcode, 1);
+ else if (geocode) shader_print_errors("linking", log, &geocode, 1);
GPU_shader_free(shader);
return NULL;
@@ -1644,6 +1865,21 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng
GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
}
+void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
+{
+ if (location == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
+
+ if (length == 1) glUniform1ivARB(location, arraysize, value);
+ else if (length == 2) glUniform2ivARB(location, arraysize, value);
+ else if (length == 3) glUniform3ivARB(location, arraysize, value);
+ else if (length == 4) glUniform4ivARB(location, arraysize, value);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
+}
+
void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
{
if (location == -1)
@@ -1652,6 +1888,13 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
GPU_CHECK_ERRORS_AROUND(glUniform1iARB(location, value));
}
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
+{
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_INPUT_TYPE_EXT, input);
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_VERTICES_OUT_EXT, number);
+}
+
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
{
GLenum arbnumber;
@@ -1699,18 +1942,41 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
switch (shader) {
case GPU_SHADER_VSM_STORE:
if (!GG.shaders.vsm_store)
- GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL);
+ GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.vsm_store;
break;
case GPU_SHADER_SEP_GAUSSIAN_BLUR:
if (!GG.shaders.sep_gaussian_blur)
- GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL);
+ GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.sep_gaussian_blur;
break;
}
if (retval == NULL)
- printf("Unable to create a GPUShader for builtin shader: %d\n", shader);
+ printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
+
+ return retval;
+}
+
+GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program)
+{
+ GPUProgram *retval = NULL;
+
+ switch (program) {
+ case GPU_PROGRAM_SMOKE:
+ if (!GG.shaders.smoke)
+ GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl);
+ retval = GG.shaders.smoke;
+ break;
+ case GPU_PROGRAM_SMOKE_COLORED:
+ if (!GG.shaders.smoke_colored)
+ GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl);
+ retval = GG.shaders.smoke_colored;
+ break;
+ }
+
+ if (retval == NULL)
+ printf("Unable to create a GPUProgram for builtin program: %u\n", program);
return retval;
}
@@ -1733,38 +1999,57 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
}
if (!GG.shaders.fx_shaders[offset]) {
- switch(effects) {
+ GPUShader *shader;
+
+ switch (effects) {
case GPU_SHADER_FX_SSAO:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
strcat(defines, "#define FIRST_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
strcat(defines, "#define SECOND_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
strcat(defines, "#define THIRD_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
strcat(defines, "#define FOURTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
strcat(defines, "#define FIFTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
+ strcat(defines, "#define FIRST_PASS\n");
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
+ strcat(defines, "#define SECOND_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
+ defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
+ GG.shaders.fx_shaders[offset] = shader;
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
+ strcat(defines, "#define THIRD_PASS\n");
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_RESOLVE:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
}
}
@@ -1777,24 +2062,63 @@ void GPU_shader_free_builtin_shaders(void)
int i;
if (GG.shaders.vsm_store) {
- MEM_freeN(GG.shaders.vsm_store);
+ GPU_shader_free(GG.shaders.vsm_store);
GG.shaders.vsm_store = NULL;
}
if (GG.shaders.sep_gaussian_blur) {
- MEM_freeN(GG.shaders.sep_gaussian_blur);
+ GPU_shader_free(GG.shaders.sep_gaussian_blur);
GG.shaders.sep_gaussian_blur = NULL;
}
+ if (GG.shaders.smoke) {
+ GPU_program_free(GG.shaders.smoke);
+ GG.shaders.smoke = NULL;
+ }
+
+ if (GG.shaders.smoke_colored) {
+ GPU_program_free(GG.shaders.smoke_colored);
+ GG.shaders.smoke_colored = NULL;
+ }
+
for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
if (GG.shaders.fx_shaders[i]) {
- MEM_freeN(GG.shaders.fx_shaders[i]);
+ GPU_shader_free(GG.shaders.fx_shaders[i]);
GG.shaders.fx_shaders[i] = NULL;
}
}
}
-#if 0
+bool GPU_mem_stats_supported(void)
+{
+ return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM);
+}
+
+
+void GPU_mem_stats_get(int *totalmem, int *freemem)
+{
+ if (GLEW_NVX_gpu_memory_info) {
+ /* returned value in Kb */
+ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
+
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
+ }
+ else if (GLEW_ATI_meminfo) {
+ int stats[4];
+
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
+ *freemem = stats[0];
+ *totalmem = 0;
+ }
+ else {
+ *totalmem = 0;
+ *freemem = 0;
+ }
+}
+
+
+#if 0 /* unused */
+
/* GPUPixelBuffer */
typedef struct GPUPixelBuffer {
@@ -1820,7 +2144,7 @@ GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffe
return NULL;
pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
- pb->datasize = x*y*4*((halffloat)? 16: 8);
+ pb->datasize = x * y * 4 * (halffloat ? 16 : 8);
pb->numbuffers = numbuffers;
pb->halffloat = halffloat;
@@ -1848,10 +2172,13 @@ void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
GL_STREAM_DRAW_ARB);
pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
- /*memcpy(pixels, _oImage.data(), pb->datasize);*/
+
+# if 0
+ memcpy(pixels, _oImage.data(), pb->datasize);
+# endif
if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap opengl PBO\n");
+ fprintf(stderr, "Could not unmap OpenGL PBO\n");
break;
}
}
@@ -1869,7 +2196,7 @@ static int pixelbuffer_map_into_gpu(GLuint bindcode)
/* do stuff in pixels */
if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap opengl PBO\n");
+ fprintf(stderr, "Could not unmap OpenGL PBO\n");
return 0;
}
@@ -1882,8 +2209,7 @@ static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLu
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
- glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
- GL_RGBA, type, NULL);
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
@@ -1898,12 +2224,12 @@ void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
pixelbuffer_map_into_gpu(pb->bindcode[0]);
}
else {
- pb->current = (pb->current+1)%pb->numbuffers;
- newbuffer = (pb->current+1)%pb->numbuffers;
+ pb->current = (pb->current + 1) % pb->numbuffers;
+ newbuffer = (pb->current + 1) % pb->numbuffers;
pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
}
}
-#endif
+#endif /* unused */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index c754f63664f..bd17fb0b1aa 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -76,6 +76,16 @@ typedef enum DynMatProperty {
DYN_LAMP_PERSMAT = 8,
} DynMatProperty;
+static struct GPUWorld {
+ float mistenabled;
+ float mistype;
+ float miststart;
+ float mistdistance;
+ float mistintensity;
+ float mistcol[4];
+ float horicol[3];
+ float ambcol[4];
+} GPUWorld;
struct GPUMaterial {
Scene *scene;
@@ -92,7 +102,6 @@ struct GPUMaterial {
/* for binding the material */
GPUPass *pass;
GPUVertexAttribs attribs;
- int bound;
int builtins;
int alpha, obcolalpha;
int dynproperty;
@@ -104,6 +113,7 @@ struct GPUMaterial {
int cameratexcofacloc;
ListBase lamps;
+ bool bound;
};
struct GPULamp {
@@ -157,7 +167,7 @@ static GPUMaterial *GPU_material_construct_begin(Material *ma)
{
GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
- material->ma= ma;
+ material->ma = ma;
return material;
}
@@ -170,14 +180,14 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
char name[32];
int a, b;
- attribs= &material->attribs;
- pass= material->pass;
+ attribs = &material->attribs;
+ pass = material->pass;
if (!pass) {
attribs->totlayer = 0;
return;
}
- shader= GPU_pass_shader(pass);
+ shader = GPU_pass_shader(pass);
if (!shader) {
attribs->totlayer = 0;
return;
@@ -187,7 +197,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
* in case the attrib does not get a valid index back, it was probably
* removed by the glsl compiler by dead code elimination */
- for (a=0, b=0; a<attribs->totlayer; a++) {
+ for (a = 0, b = 0; a < attribs->totlayer; a++) {
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
@@ -242,19 +252,19 @@ void GPU_material_free(ListBase *gpumaterial)
LinkData *link;
LinkData *nlink, *mlink, *next;
- for (link=gpumaterial->first; link; link=link->next) {
+ for (link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
if (material->pass)
GPU_pass_free(material->pass);
- for (nlink=material->lamps.first; nlink; nlink=nlink->next) {
+ for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
GPULamp *lamp = nlink->data;
if (material->ma) {
Material *ma = material->ma;
- for (mlink=lamp->materials.first; mlink; mlink=next) {
+ for (mlink = lamp->materials.first; mlink; mlink = next) {
next = mlink->next;
if (mlink->data == ma)
BLI_freelinkN(&lamp->materials, mlink);
@@ -293,8 +303,8 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
/* handle layer lamps */
if (material->type == GPU_MATERIAL_TYPE_MESH) {
- for (nlink=material->lamps.first; nlink; nlink=nlink->next) {
- lamp= nlink->data;
+ for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
+ lamp = nlink->data;
if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay))
&& GPU_lamp_override_visible(lamp, srl, material->ma)) {
@@ -303,7 +313,7 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
}
else {
lamp->dynenergy = 0.0f;
- lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f;
+ lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f;
}
if (material->dynproperty & DYN_LAMP_VEC) {
@@ -390,7 +400,7 @@ void GPU_material_unbind(GPUMaterial *material)
}
}
-int GPU_material_bound(GPUMaterial *material)
+bool GPU_material_bound(GPUMaterial *material)
{
return material->bound;
}
@@ -414,12 +424,12 @@ void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *att
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
if (!material->outlink)
- material->outlink= link;
+ material->outlink = link;
}
void GPU_material_enable_alpha(GPUMaterial *material)
{
- material->alpha= 1;
+ material->alpha = 1;
}
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4])
@@ -442,7 +452,7 @@ bool GPU_material_do_color_management(GPUMaterial *mat)
if (!BKE_scene_check_color_management_enabled(mat->scene))
return false;
- return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT));
+ return true;
}
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
@@ -455,7 +465,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
GPUNodeLink *visifac, *inpr;
/* from get_lamp_visibility */
- if (lamp->type==LA_SUN || lamp->type==LA_HEMI) {
+ if (lamp->type == LA_SUN || lamp->type == LA_HEMI) {
mat->dynproperty |= DYN_LAMP_VEC;
GPU_link(mat, "lamp_visibility_sun_hemi", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
return visifac;
@@ -464,7 +474,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
mat->dynproperty |= DYN_LAMP_CO;
GPU_link(mat, "lamp_visibility_other", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
- if (lamp->type==LA_AREA)
+ if (lamp->type == LA_AREA)
return visifac;
switch (lamp->falloff_type) {
@@ -480,15 +490,16 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
GPU_link(mat, "lamp_falloff_sliders", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_CURVE:
- {
- float *array;
- int size;
+ {
+ float *array;
+ int size;
+
+ curvemapping_initialize(lamp->curfalloff);
+ curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
+ GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac);
- curvemapping_initialize(lamp->curfalloff);
- curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
- GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac);
- }
break;
+ }
}
if (lamp->mode & LA_SPHERE)
@@ -516,34 +527,34 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
#if 0
static void area_lamp_vectors(LampRen *lar)
{
- float xsize= 0.5*lar->area_size, ysize= 0.5*lar->area_sizey, multifac;
+ float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey, multifac;
/* make it smaller, so area light can be multisampled */
- multifac= 1.0f/sqrt((float)lar->ray_totsamp);
+ multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
xsize *= multifac;
ysize *= multifac;
/* corner vectors */
- lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
+ lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
+ lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+ lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
+ lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
+ lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+ lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
+ lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
+ lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
+ lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
+ lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* only for correction button size, matrix size works on energy */
- lar->areasize= lar->dist*lar->dist/(4.0*xsize*ysize);
+ lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize);
}
#endif
@@ -577,8 +588,8 @@ static void do_colorband_blend(GPUMaterial *mat, ColorBand *coba, GPUNodeLink *f
static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) {
@@ -607,18 +618,18 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
else {
/* input */
switch (ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
- break;
- case MA_RAMP_IN_SHADER:
- fac= is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
+ case MA_RAMP_IN_ENERGY:
+ GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac= is;
+ break;
+ case MA_RAMP_IN_NOR:
+ GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
+ break;
+ default:
+ GPU_link(mat, "set_value_zero", &fac);
+ break;
}
/* colorband + blend */
@@ -634,12 +645,12 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
- ma->ramp_spec && ma->rampin_spec==MA_RAMP_IN_RESULT)
+ ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT)
{
GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
@@ -650,29 +661,29 @@ static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac, *tmp;
*spec = shi->specrgb;
/* MA_RAMP_IN_RESULT is exception */
- if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
+ if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) {
/* input */
switch (ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac = t;
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
+ case MA_RAMP_IN_ENERGY:
+ fac = t;
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac = is;
+ break;
+ case MA_RAMP_IN_NOR:
+ GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
+ break;
+ default:
+ GPU_link(mat, "set_value_zero", &fac);
+ break;
}
/* colorband + blend */
@@ -694,10 +705,10 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
int i;
float one = 1.f;
- for (i=0; i<MAX_MTEX; ++i) {
+ for (i = 0; i < MAX_MTEX; ++i) {
mtex = lamp->la->mtex[i];
- if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
+ if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
GPU_link(mat, "shade_light_texture",
@@ -705,29 +716,31 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
&tex_rgb);
- texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
+ texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
}
}
}
static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *lv, *dist, *visifac, *is, *inp, *i, *vn, *view;
- GPUNodeLink *outcol, *specfac, *t, *shadfac= NULL, *lcol;
+ GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol;
float one = 1.0f;
if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW))
return;
- vn= shi->vn;
- view= shi->view;
+ vn = shi->vn;
+ view = shi->view;
- visifac= lamp_get_visibility(mat, lamp, &lv, &dist);
+ visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
- /*if (ma->mode & MA_TANGENT_V)
- GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);*/
+#if 0
+ if (ma->mode & MA_TANGENT_V)
+ GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);
+#endif
GPU_link(mat, "shade_inp", vn, lv, &inp);
@@ -739,23 +752,23 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
}
else {
if (lamp->type == LA_AREA) {
- float area[4][4]= {{0.0f}}, areasize= 0.0f;
+ float area[4][4] = {{0.0f}}, areasize = 0.0f;
mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_CO;
GPU_link(mat, "shade_inp_area", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, GPU_uniform((float*)area),
GPU_uniform(&areasize), GPU_uniform(&lamp->k), &inp);
}
- is= inp; /* Lambert */
+ is = inp; /* Lambert */
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) {
- if (ma->diff_shader==MA_DIFF_ORENNAYAR)
+ if (ma->diff_shader == MA_DIFF_ORENNAYAR)
GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view, GPU_uniform(&ma->roughness), &is);
- else if (ma->diff_shader==MA_DIFF_TOON)
+ else if (ma->diff_shader == MA_DIFF_TOON)
GPU_link(mat, "shade_diffuse_toon", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
- else if (ma->diff_shader==MA_DIFF_MINNAERT)
+ else if (ma->diff_shader == MA_DIFF_MINNAERT)
GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view, GPU_uniform(&ma->darkness), &is);
- else if (ma->diff_shader==MA_DIFF_FRESNEL)
+ else if (ma->diff_shader == MA_DIFF_FRESNEL)
GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
}
}
@@ -777,7 +790,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
#endif
/* this replaces if (i > 0.0) conditional until that is supported */
- // done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i);
+ /* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */
if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) {
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) {
@@ -850,18 +863,18 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
else {
- if (ma->spec_shader==MA_SPEC_PHONG)
+ if (ma->spec_shader == MA_SPEC_PHONG)
GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_COOKTORR)
+ else if (ma->spec_shader == MA_SPEC_COOKTORR)
GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_BLINN)
+ else if (ma->spec_shader == MA_SPEC_BLINN)
GPU_link(mat, "shade_blinn_spec", vn, lv, view, GPU_uniform(&ma->refrac), shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_WARDISO)
+ else if (ma->spec_shader == MA_SPEC_WARDISO)
GPU_link(mat, "shade_wardiso_spec", vn, lv, view, GPU_uniform(&ma->rms), &specfac);
else
GPU_link(mat, "shade_toon_spec", vn, lv, view, GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
- if (lamp->type==LA_AREA)
+ if (lamp->type == LA_AREA)
GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac);
GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t);
@@ -891,9 +904,9 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
GPULamp *lamp;
for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) {
- ob= base->object;
+ ob = base->object;
- if (ob->type==OB_LAMP) {
+ if (ob->type == OB_LAMP) {
lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
if (lamp)
shade_one_light(shi, shr, lamp);
@@ -903,10 +916,10 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
DupliObject *dob;
ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob);
- for (dob=lb->first; dob; dob=dob->next) {
+ for (dob = lb->first; dob; dob = dob->next) {
Object *ob_iter = dob->ob;
- if (ob_iter->type==OB_LAMP) {
+ if (ob_iter->type == OB_LAMP) {
float omat[4][4];
copy_m4_m4(omat, ob_iter->obmat);
copy_m4_m4(ob_iter->obmat, dob->mat);
@@ -1023,8 +1036,8 @@ static void texture_value_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink
static void do_material_tex(GPUShadeInput *shi)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
MTex *mtex;
Tex *tex;
GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac;
@@ -1035,9 +1048,9 @@ static void do_material_tex(GPUShadeInput *shi)
float one = 1.0f, norfac, ofs[3];
int tex_nr, rgbnor, talpha;
bool init_done = false;
- int iBumpSpacePrev = 0; /* Not necessary, quiting gcc warning. */
+ int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */
GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude;
- int iFirstTimeNMap=1;
+ int iFirstTimeNMap = 1;
int found_deriv_map = 0;
GPU_link(mat, "set_value", GPU_uniform(&one), &stencil);
@@ -1047,44 +1060,46 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_object);
- //GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
+#if 0
+ GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
+#endif
GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_global);
orn= texco_norm;
/* go over texture slots */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
+ for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
/* separate tex switching */
- if (ma->septex & (1<<tex_nr)) continue;
+ if (ma->septex & (1 << tex_nr)) continue;
if (ma->mtex[tex_nr]) {
- mtex= ma->mtex[tex_nr];
+ mtex = ma->mtex[tex_nr];
- tex= mtex->tex;
+ tex = mtex->tex;
if (tex == NULL) continue;
/* which coords */
- if (mtex->texco==TEXCO_ORCO)
- texco= texco_orco;
- else if (mtex->texco==TEXCO_OBJECT)
- texco= texco_object;
- else if (mtex->texco==TEXCO_NORM)
- texco= orn;
- else if (mtex->texco==TEXCO_TANGENT)
- texco= texco_object;
- else if (mtex->texco==TEXCO_GLOB)
- texco= texco_global;
- else if (mtex->texco==TEXCO_REFL) {
+ if (mtex->texco == TEXCO_ORCO)
+ texco = texco_orco;
+ else if (mtex->texco == TEXCO_OBJECT)
+ texco = texco_object;
+ else if (mtex->texco == TEXCO_NORM)
+ texco = orn;
+ else if (mtex->texco == TEXCO_TANGENT)
+ texco = texco_object;
+ else if (mtex->texco == TEXCO_GLOB)
+ texco = texco_global;
+ else if (mtex->texco == TEXCO_REFL) {
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
- texco= shi->ref;
+ texco = shi->ref;
}
- else if (mtex->texco==TEXCO_UV) {
+ else if (mtex->texco == TEXCO_UV) {
if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) {
GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv);
/*lastuvname = mtex->uvname;*/ /*UNUSED*/
}
- texco= texco_uv;
+ texco = texco_uv;
}
else
continue;
@@ -1096,8 +1111,8 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f)
GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco);
- ofs[0] = mtex->ofs[0] + 0.5f - 0.5f*mtex->size[0];
- ofs[1] = mtex->ofs[1] + 0.5f - 0.5f*mtex->size[1];
+ ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
+ ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
ofs[2] = 0.0f;
if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
@@ -1106,7 +1121,7 @@ static void do_material_tex(GPUShadeInput *shi)
if (tex && tex->type == TEX_IMAGE && tex->ima) {
GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
- rgbnor= TEX_RGB;
+ rgbnor = TEX_RGB;
talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0);
}
@@ -1151,7 +1166,7 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "set_value_one", &tin);
}
- if (tex->type==TEX_IMAGE)
+ if (tex->type == TEX_IMAGE)
if (GPU_material_do_color_management(mat))
GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol);
@@ -1175,7 +1190,7 @@ static void do_material_tex(GPUShadeInput *shi)
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) {
- if (tex->type==TEX_IMAGE) {
+ if (tex->type == TEX_IMAGE) {
found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP;
if (tex->imaflag & TEX_NORMALMAP) {
@@ -1225,43 +1240,43 @@ static void do_material_tex(GPUShadeInput *shi)
}
}
- else if ( (mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP)) || found_deriv_map) {
+ else if ((mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) || found_deriv_map) {
/* ntap bumpmap image */
int iBumpSpace;
float ima_x, ima_y;
float hScale;
- float imag_tspace_dimension_x = 1024.0f; // only used for texture space variant
+ float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */
float aspect = 1.0f;
GPUNodeLink *vR1, *vR2;
GPUNodeLink *dBs, *dBt, *fDet;
- hScale = 0.1; // compatibility adjustment factor for all bumpspace types
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
- hScale = 13.0f; // factor for scaling texspace bumps
+ hScale = 0.1; /* compatibility adjustment factor for all bumpspace types */
+ if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
+ hScale = 13.0f; /* factor for scaling texspace bumps */
else if (found_deriv_map!=0)
hScale = 1.0f;
- // resolve texture resolution
- if ( (mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map ) {
- ImBuf *ibuf= BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- ima_x= 512.0f; ima_y= 512.f; // prevent calling textureSize, glsl 1.3 only
+ /* resolve texture resolution */
+ if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
+ ima_x = 512.0f; ima_y = 512.f; /* prevent calling textureSize, glsl 1.3 only */
if (ibuf) {
- ima_x= ibuf->x;
- ima_y= ibuf->y;
- aspect = ((float) ima_y) / ima_x;
+ ima_x = ibuf->x;
+ ima_y = ibuf->y;
+ aspect = (float)ima_y / ima_x;
}
BKE_image_release_ibuf(tex->ima, ibuf, NULL);
}
- // The negate on norfac is done because the
- // normal in the renderer points inward which corresponds
- // to inverting the bump map. Should this ever change
- // this negate must be removed.
+ /* The negate on norfac is done because the
+ * normal in the renderer points inward which corresponds
+ * to inverting the bump map. Should this ever change
+ * this negate must be removed. */
norfac = -hScale * mtex->norfac;
if (found_deriv_map) {
- float fVirtDim = sqrtf(fabsf(ima_x*mtex->size[0]*ima_y*mtex->size[1]));
+ float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1]));
norfac /= MAX2(fVirtDim, FLT_EPSILON);
}
@@ -1273,26 +1288,26 @@ static void do_material_tex(GPUShadeInput *shi)
if (GPU_link_changed(stencil))
GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
- if ( !init_done ) {
- // copy shi->vn to vNorg and vNacc, set magnitude to 1
+ if (!init_done) {
+ /* copy shi->vn to vNorg and vNacc, set magnitude to 1 */
GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude);
iBumpSpacePrev = 0;
init_done = true;
}
// find current bump space
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
+ if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
iBumpSpace = 1;
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
+ else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
iBumpSpace = 2;
else
- iBumpSpace = 4; // ViewSpace
+ iBumpSpace = 4; /* ViewSpace */
- // re-initialize if bump space changed
- if ( iBumpSpacePrev != iBumpSpace ) {
+ /* re-initialize if bump space changed */
+ if (iBumpSpacePrev != iBumpSpace) {
GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION);
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
+ if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
GPU_link(mat, "mtex_bump_init_objspace",
surf_pos, vNorg,
GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
@@ -1300,7 +1315,7 @@ static void do_material_tex(GPUShadeInput *shi)
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
+ else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
GPU_link(mat, "mtex_bump_init_texturespace",
surf_pos, vNorg,
fPrevMagnitude, vNacc,
@@ -1321,17 +1336,17 @@ static void do_material_tex(GPUShadeInput *shi)
if (found_deriv_map) {
GPU_link(mat, "mtex_bump_deriv",
texco, GPU_image(tex->ima, &tex->iuser, true), GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
- &dBs, &dBt );
+ &dBs, &dBt);
}
- else if ( mtex->texflag & MTEX_3TAP_BUMP)
+ else if (mtex->texflag & MTEX_3TAP_BUMP)
GPU_link(mat, "mtex_bump_tap3",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt );
- else if ( mtex->texflag & MTEX_5TAP_BUMP)
+ &dBs, &dBt);
+ else if (mtex->texflag & MTEX_5TAP_BUMP)
GPU_link(mat, "mtex_bump_tap5",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt );
- else if ( mtex->texflag & MTEX_BICUBIC_BUMP ) {
+ &dBs, &dBt);
+ else if (mtex->texflag & MTEX_BICUBIC_BUMP) {
if (GPU_bicubic_bump_support()) {
GPU_link(mat, "mtex_bump_bicubic",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
@@ -1345,18 +1360,18 @@ static void do_material_tex(GPUShadeInput *shi)
}
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- float imag_tspace_dimension_y = aspect*imag_tspace_dimension_x;
+ if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) {
+ float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x;
GPU_link(mat, "mtex_bump_apply_texspace",
fDet, dBs, dBt, vR1, vR2,
GPU_image(tex->ima, &tex->iuser, true), texco,
GPU_uniform(&imag_tspace_dimension_x), GPU_uniform(&imag_tspace_dimension_y), vNacc,
- &vNacc, &shi->vn );
+ &vNacc, &shi->vn);
}
else
GPU_link(mat, "mtex_bump_apply",
fDet, dBs, dBt, vR1, vR2, vNacc,
- &vNacc, &shi->vn );
+ &vNacc, &shi->vn);
}
}
@@ -1434,7 +1449,6 @@ static void do_material_tex(GPUShadeInput *shi)
void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
{
- float hard = ma->har;
float one = 1.0f;
memset(shi, 0, sizeof(*shi));
@@ -1442,20 +1456,20 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
shi->gpumat = mat;
shi->mat = ma;
- GPU_link(mat, "set_rgb", GPU_uniform(&ma->r), &shi->rgb);
- GPU_link(mat, "set_rgb", GPU_uniform(&ma->specr), &shi->specrgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
- GPU_link(mat, "set_value", GPU_uniform(&ma->alpha), &shi->alpha);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, NULL), &shi->alpha);
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
- GPU_link(mat, "set_value", GPU_uniform(&ma->ref), &shi->refl);
- GPU_link(mat, "set_value", GPU_uniform(&ma->spec), &shi->spec);
- GPU_link(mat, "set_value", GPU_uniform(&ma->emit), &shi->emit);
- GPU_link(mat, "set_value", GPU_uniform(&hard), &shi->har);
- GPU_link(mat, "set_value", GPU_uniform(&ma->amb), &shi->amb);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform((float*)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
@@ -1464,13 +1478,39 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
}
+void GPU_mist_update_enable(short enable)
+{
+ GPUWorld.mistenabled = (float)enable;
+}
+
+void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3])
+{
+ GPUWorld.mistype = (float)type;
+ GPUWorld.miststart = start;
+ GPUWorld.mistdistance = dist;
+ GPUWorld.mistintensity = inten;
+ copy_v3_v3(GPUWorld.mistcol, color);
+ GPUWorld.mistcol[3] = 1.0f;
+}
+
+void GPU_horizon_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.horicol, color);
+}
+
+void GPU_ambient_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.ambcol, color);
+ GPUWorld.ambcol[3] = 1.0f;
+}
+
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
- GPUMaterial *mat= shi->gpumat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac;
- Material *ma= shi->mat;
- World *world= mat->scene->world;
- float linfac, logfac, misttype;
+ Material *ma = shi->mat;
+ World *world = mat->scene->world;
+ float linfac, logfac;
memset(shr, 0, sizeof(*shr));
@@ -1487,7 +1527,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
else {
if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) {
- if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL) {
+ if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) == MA_VERTEXCOL) {
GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit);
GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff);
}
@@ -1507,9 +1547,9 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
if (world) {
/* exposure correction */
- if (world->exp!=0.0f || world->range!=1.0f) {
- linfac= 1.0f + powf((2.0f*world->exp + 0.5f), -10);
- logfac= logf((linfac-1.0f)/linfac)/world->range;
+ if (world->exp != 0.0f || world->range != 1.0f) {
+ linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10);
+ logfac = logf((linfac - 1.0f) / linfac) / world->range;
GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac);
GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac);
@@ -1521,10 +1561,10 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
/* ambient color */
- if (world->ambr!=0.0f || world->ambg!=0.0f || world->ambb!=0.0f) {
- if (GPU_link_changed(shi->amb) || ma->amb != 0.0f)
- GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
- GPU_uniform(&world->ambr), &shr->combined);
+ if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
+ GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
+ GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL),
+ &shr->combined);
}
}
@@ -1546,21 +1586,22 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
if (ma->shade_flag & MA_OBCOLOR)
GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
- if (world && (world->mode & WO_MIST) && !(ma->mode & MA_NOMIST)) {
- misttype = world->mistype;
-
+ if (!(ma->mode & MA_NOMIST)) {
GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION),
- GPU_uniform(&world->miststa), GPU_uniform(&world->mistdist),
- GPU_uniform(&misttype), GPU_uniform(&world->misi), &mistfac);
+ GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac);
GPU_link(mat, "mix_blend", mistfac, shr->combined,
- GPU_uniform(&world->horr), &shr->combined);
+ GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined);
}
if (!mat->alpha) {
if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f))
- GPU_link(mat, "shade_world_mix", GPU_uniform(&world->horr),
- shr->combined, &shr->combined);
+ GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
+ shr->combined, &shr->combined);
GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined);
}
@@ -1612,7 +1653,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma)
GPUNodeLink *outlink;
LinkData *link;
- for (link=ma->gpumaterial.first; link; link=link->next)
+ for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1648,7 +1689,7 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
LinkData *link;
GPUMaterial *mat;
- for (link=wo->gpumaterial.first; link; link=link->next)
+ for (link = wo->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1688,7 +1729,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma)
GPUNodeLink *outlink;
LinkData *link;
- for (link=ma->gpumaterial.first; link; link=link->next)
+ for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1745,15 +1786,15 @@ void GPU_materials_free(void)
World *wo;
extern Material defmaterial;
- for (ma=G.main->mat.first; ma; ma=ma->id.next)
+ for (ma = G.main->mat.first; ma; ma = ma->id.next)
GPU_material_free(&ma->gpumaterial);
- for (wo=G.main->world.first; wo; wo=wo->id.next)
+ for (wo = G.main->world.first; wo; wo = wo->id.next)
GPU_material_free(&wo->gpumaterial);
GPU_material_free(&defmaterial.gpumaterial);
- for (ob=G.main->object.first; ob; ob=ob->id.next)
+ for (ob = G.main->object.first; ob; ob = ob->id.next)
GPU_lamp_free(ob);
}
@@ -1795,11 +1836,11 @@ void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
{
lamp->energy = energy;
- if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
- lamp->col[0]= r;
- lamp->col[1]= g;
- lamp->col[2]= b;
+ lamp->col[0] = r;
+ lamp->col[1] = g;
+ lamp->col[2] = b;
}
void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2)
@@ -1829,11 +1870,11 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->type = la->type;
lamp->energy = la->energy;
- if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
- lamp->col[0]= la->r;
- lamp->col[1]= la->g;
- lamp->col[2]= la->b;
+ lamp->col[0] = la->r;
+ lamp->col[1] = la->g;
+ lamp->col[2] = la->b;
GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat);
@@ -1842,20 +1883,20 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
if (lamp->spotsi > DEG2RADF(170.0f))
lamp->spotsi = DEG2RADF(170.0f);
lamp->spotsi = cosf(lamp->spotsi * 0.5f);
- lamp->spotbl= (1.0f - lamp->spotsi)*la->spotblend;
- lamp->k= la->k;
+ lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend;
+ lamp->k = la->k;
- lamp->dist= la->dist;
- lamp->falloff_type= la->falloff_type;
- lamp->att1= la->att1;
- lamp->att2= la->att2;
- lamp->curfalloff= la->curfalloff;
+ lamp->dist = la->dist;
+ lamp->falloff_type = la->falloff_type;
+ lamp->att1 = la->att1;
+ lamp->att2 = la->att2;
+ lamp->curfalloff = la->curfalloff;
/* initshadowbuf */
- lamp->bias = 0.02f*la->bias;
+ lamp->bias = 0.02f * la->bias;
lamp->size = la->bufsize;
- lamp->d= la->clipsta;
- lamp->clipend= la->clipend;
+ lamp->d = la->clipsta;
+ lamp->clipend = la->clipend;
/* arbitrary correction for the fact we do no soft transition */
lamp->bias *= 0.25f;
@@ -1868,23 +1909,23 @@ static void gpu_lamp_shadow_free(GPULamp *lamp)
{
if (lamp->tex) {
GPU_texture_free(lamp->tex);
- lamp->tex= NULL;
+ lamp->tex = NULL;
}
if (lamp->depthtex) {
GPU_texture_free(lamp->depthtex);
- lamp->depthtex= NULL;
+ lamp->depthtex = NULL;
}
if (lamp->fb) {
GPU_framebuffer_free(lamp->fb);
- lamp->fb= NULL;
+ lamp->fb = NULL;
}
if (lamp->blurtex) {
GPU_texture_free(lamp->blurtex);
- lamp->blurtex= NULL;
+ lamp->blurtex = NULL;
}
if (lamp->blurfb) {
GPU_framebuffer_free(lamp->blurfb);
- lamp->blurfb= NULL;
+ lamp->blurfb = NULL;
}
}
@@ -1894,7 +1935,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
GPULamp *lamp;
LinkData *link;
- for (link=ob->gpulamp.first; link; link=link->next) {
+ for (link = ob->gpulamp.first; link; link = link->next) {
lamp = (GPULamp*)link->data;
if (lamp->par == par && lamp->scene == scene)
@@ -1910,7 +1951,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
la = ob->data;
gpu_lamp_from_blender(scene, ob, par, la, lamp);
- if ((la->type==LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type==LA_SUN && (la->mode & LA_SHAD_RAY))) {
+ if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) {
/* opengl */
lamp->fb = GPU_framebuffer_create();
if (!lamp->fb) {
@@ -1955,7 +1996,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
return lamp;
}
- lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size*0.5, NULL);
+ lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL);
if (!lamp->blurtex) {
gpu_lamp_shadow_free(lamp);
return lamp;
@@ -2016,7 +2057,7 @@ void GPU_lamp_free(Object *ob)
LinkData *nlink;
Material *ma;
- for (link=ob->gpulamp.first; link; link=link->next) {
+ for (link = ob->gpulamp.first; link; link = link->next) {
lamp = link->data;
while (lamp->materials.first) {
@@ -2264,7 +2305,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
break;
}
- if (uniform->type >= GPU_DYNAMIC_LAMP_FIRST && uniform->type <= GPU_DYNAMIC_LAMP_LAST)
+ if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
uniform->lamp = input->dynamicdata;
}
@@ -2275,7 +2316,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
}
/* process builtin uniform */
- for (i=0; builtins[i].gputype; i++) {
+ for (i = 0; builtins[i].gputype; i++) {
if (mat->builtins & builtins[i].gputype) {
uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
uniform->type = builtins[i].dynamictype;
@@ -2289,14 +2330,14 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
/* TBD: remove the function that are not used in the main function */
liblen = (pass->libcode) ? strlen(pass->libcode) : 0;
fraglen = strlen(pass->fragmentcode);
- shader->fragment = (char *)MEM_mallocN(liblen+fraglen+1, "GPUFragShader");
+ shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader");
if (pass->libcode)
memcpy(shader->fragment, pass->libcode, liblen);
memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen);
- shader->fragment[liblen+fraglen] = 0;
+ shader->fragment[liblen + fraglen] = 0;
// export the attribute
- for (i=0; i<mat->attribs.totlayer; i++) {
+ for (i = 0; i < mat->attribs.totlayer; i++) {
attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
attribute->type = mat->attribs.layer[i].type;
attribute->number = mat->attribs.layer[i].glindex;
@@ -2325,7 +2366,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
MEM_freeN(attribute);
}
- // export the vertex shader
+ /* export the vertex shader */
shader->vertex = BLI_strdup(pass->vertexcode);
}
@@ -2339,7 +2380,7 @@ void GPU_free_shader_export(GPUShaderExport *shader)
if (shader == NULL)
return;
- for (uniform = shader->uniforms.first; uniform; uniform=uniform->next)
+ for (uniform = shader->uniforms.first; uniform; uniform = uniform->next)
if (uniform->texpixels)
MEM_freeN(uniform->texpixels);
diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c
index 3fa5975ef15..b439a37f3c3 100644
--- a/source/blender/gpu/intern/gpu_simple_shader.c
+++ b/source/blender/gpu/intern/gpu_simple_shader.c
@@ -151,7 +151,8 @@ static GPUShader *gpu_simple_shader(int options)
shader = GPU_shader_create(
datatoc_gpu_shader_simple_vert_glsl,
datatoc_gpu_shader_simple_frag_glsl,
- NULL, defines);
+ NULL,
+ NULL, defines, 0, 0, 0);
if (shader) {
/* set texture map to first texture unit */
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
new file mode 100644
index 00000000000..a94c823f408
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
@@ -0,0 +1,32 @@
+!!ARBfp1.0
+PARAM dx = program.local[0];
+PARAM darkness = program.local[1];
+PARAM render = program.local[2];
+PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};
+TEMP temp, shadow, flame, spec, value;
+TEX temp, fragment.texcoord[0], texture[0], 3D;
+TEX shadow, fragment.texcoord[0], texture[1], 3D;
+TEX flame, fragment.texcoord[0], texture[2], 3D;
+TEX spec, flame.r, texture[3], 1D;
+# unpremultiply volume texture
+RCP value.r, temp.a;
+MUL temp.r, temp.r, value.r;
+MUL temp.g, temp.g, value.r;
+MUL temp.b, temp.b, value.r;
+# calculate shading factor from density
+MUL value.r, temp.a, darkness.a;
+MUL value.r, value.r, dx.r;
+MUL value.r, value.r, f.r;
+EX2 value.r, -value.r;
+# alpha
+SUB temp.a, 1.0, value.r;
+# shade colors
+MUL temp.r, temp.r, shadow.r;
+MUL temp.g, temp.g, shadow.r;
+MUL temp.b, temp.b, shadow.r;
+MUL temp.r, temp.r, value.r;
+MUL temp.g, temp.g, value.r;
+MUL temp.b, temp.b, value.r;
+# for now this just replace smoke shading if rendering fire
+CMP result.color, render.r, temp, spec;
+END
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
new file mode 100644
index 00000000000..04b171d24bd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
@@ -0,0 +1,27 @@
+!!ARBfp1.0
+PARAM dx = program.local[0];
+PARAM darkness = program.local[1];
+PARAM render = program.local[2];
+PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};
+TEMP temp, shadow, flame, spec, value;
+TEX temp, fragment.texcoord[0], texture[0], 3D;
+TEX shadow, fragment.texcoord[0], texture[1], 3D;
+TEX flame, fragment.texcoord[0], texture[2], 3D;
+TEX spec, flame.r, texture[3], 1D;
+# calculate shading factor from density
+MUL value.r, temp.a, darkness.a;
+MUL value.r, value.r, dx.r;
+MUL value.r, value.r, f.r;
+EX2 temp, -value.r;
+# alpha
+SUB temp.a, 1.0, temp.r;
+# shade colors
+MUL temp.r, temp.r, shadow.r;
+MUL temp.g, temp.g, shadow.r;
+MUL temp.b, temp.b, shadow.r;
+MUL temp.r, temp.r, darkness.r;
+MUL temp.g, temp.g, darkness.g;
+MUL temp.b, temp.b, darkness.b;
+# for now this just replace smoke shading if rendering fire
+CMP result.color, render.r, temp, spec;
+END
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
new file mode 100644
index 00000000000..e315d2fb97a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -0,0 +1,166 @@
+/* amount of offset to move one pixel left-right.
+ * In second pass some dimensions are zero to control verical/horizontal convolution */
+uniform vec2 invrendertargetdim;
+
+uniform ivec2 rendertargetdim;
+
+/* color buffer */
+uniform sampler2D colorbuffer;
+uniform sampler2D farbuffer;
+uniform sampler2D nearbuffer;
+
+/* depth buffer */
+uniform sampler2D depthbuffer;
+
+uniform sampler2D cocbuffer;
+
+/* this includes focal distance in x and aperture size in y */
+uniform vec4 dof_params;
+
+/* viewvectors for reconstruction of world space */
+uniform vec4 viewvecs[3];
+
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+varying vec4 color;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* calculate 4 samples at once */
+vec4 calculate_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_params.z;
+}
+
+#define THRESHOLD 0.0
+
+/* downsample the color buffer to half resolution */
+void downsample_pass()
+{
+ vec4 depth;
+ vec4 zdepth;
+ vec4 coc;
+ float far_coc, near_coc;
+
+ /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */
+ vec4 color1 = texture2D(colorbuffer, downsample1);
+ vec4 color2 = texture2D(colorbuffer, downsample2);
+ vec4 color3 = texture2D(colorbuffer, downsample3);
+ vec4 color4 = texture2D(colorbuffer, downsample4);
+
+ depth.r = texture2D(depthbuffer, downsample1).r;
+ depth.g = texture2D(depthbuffer, downsample2).r;
+ depth.b = texture2D(depthbuffer, downsample3).r;
+ depth.a = texture2D(depthbuffer, downsample4).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = calculate_coc(zdepth);
+ vec4 coc_far = -coc;
+
+ /* now we need to write the near-far fields premultiplied by the coc */
+ vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0);
+ vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0);
+
+ near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0);
+ far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0);
+
+ float norm_near = dot(near_weights, vec4(1.0));
+ float norm_far = dot(far_weights, vec4(1.0));
+
+ /* now write output to weighted buffers. */
+ gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z +
+ color4 * near_weights.w;
+ gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z +
+ color4 * far_weights.w;
+
+ if (norm_near > 0.0)
+ gl_FragData[0] /= norm_near;
+ if (norm_far > 0.0)
+ gl_FragData[1] /= norm_far;
+ gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0);
+}
+
+/* accumulate color in the near/far blur buffers */
+void accumulate_pass(void) {
+ float theta = atan(particlecoord.y, particlecoord.x);
+ float r;
+
+ if (dof_params.w == 0.0)
+ r = 1.0;
+ else
+ r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+
+ if (dot(particlecoord, particlecoord) > r * r)
+ discard;
+
+ gl_FragData[0] = color;
+}
+#define MERGE_THRESHOLD 4.0
+
+/* combine the passes, */
+void final_pass(void) {
+ vec4 finalcolor;
+ float totalweight;
+ float depth = texture2D(depthbuffer, uvcoord).r;
+
+ vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth));
+ float coc_near = calculate_coc(zdepth).r;
+ float coc_far = max(-coc_near, 0.0);
+ coc_near = max(coc_near, 0.0);
+
+ vec4 farcolor = texture2D(farbuffer, uvcoord);
+ float farweight = farcolor.a;
+ if (farweight > 0.0)
+ farcolor /= farweight;
+ vec4 nearcolor = texture2D(nearbuffer, uvcoord);
+
+ vec4 srccolor = texture2D(colorbuffer, uvcoord);
+
+ vec4 coc = texture2D(cocbuffer, uvcoord);
+
+ float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
+ finalcolor = mix(srccolor, farcolor, mixfac);
+
+ farweight = mix(1.0, farweight, mixfac);
+
+ float nearweight = nearcolor.a;
+ if (nearweight > 0.0) {
+ nearcolor /= nearweight;
+ }
+
+ if (coc_near > 1.0) {
+ nearweight = 1.0;
+ finalcolor = nearcolor;
+ }
+ else {
+ totalweight = nearweight + farweight;
+ finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight);
+ }
+
+ gl_FragData[0] = finalcolor;
+}
+
+void main()
+{
+#ifdef FIRST_PASS
+ downsample_pass();
+#elif defined(SECOND_PASS)
+ accumulate_pass();
+#elif defined(THIRD_PASS)
+ final_pass();
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
new file mode 100644
index 00000000000..7918122a681
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
@@ -0,0 +1,50 @@
+uniform ivec2 rendertargetdim;
+uniform sampler2D colorbuffer;
+
+uniform vec2 layerselection;
+
+uniform sampler2D cocbuffer;
+
+/* initial uv coordinate */
+varying in vec2 uvcoord[1];
+varying out vec2 particlecoord;
+varying out vec4 color;
+
+
+#define M_PI 3.1415926535897932384626433832795
+
+void main(void)
+{
+ vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0);
+
+ float offset_val = dot(coc.rg, layerselection);
+ if (offset_val < 1.0)
+ return;
+
+ vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0);
+
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (offset_val * offset_val * M_PI);
+ colortex *= alpha;
+ colortex.a = alpha;
+
+ vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y);
+
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ color = colortex;
+ particlecoord = vec2(-1.0, -1.0);
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(-1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, -1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
new file mode 100644
index 00000000000..09a0c75facc
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
@@ -0,0 +1,58 @@
+uniform vec2 invrendertargetdim;
+uniform ivec2 rendertargetdim;
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+void vert_dof_downsample()
+{
+ /* gather pixels from neighbors. half dimensions means we offset half a pixel to
+ * get this right though it's possible we may lose a pixel at some point */
+ downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim;
+ downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim;
+ downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim;
+ downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim;
+
+ gl_Position = gl_Vertex;
+}
+
+/* geometry shading pass, calculate a texture coordinate based on the indexed id */
+void vert_dof_coc_scatter_pass()
+{
+ vec2 pixel = vec2(rendertargetdim.x, rendertargetdim.y);
+ /* some math to get the target pixel */
+ int row = gl_InstanceID / rendertargetdim.x;
+ int column = gl_InstanceID % rendertargetdim.x;
+ uvcoord = (vec2(column, row) + vec2(0.5)) / pixel;
+
+ vec2 pos = uvcoord * 2.0 - vec2(1.0);
+ gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
+
+// uvcoord = vec2(0.5, 0.5);
+// gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void vert_dof_final()
+{
+ uvcoord = gl_MultiTexCoord0.xy;
+ gl_Position = gl_Vertex;
+}
+
+void main()
+{
+#if defined(FIRST_PASS)
+ vert_dof_downsample();
+#elif defined(SECOND_PASS)
+ vert_dof_coc_scatter_pass();
+#else
+ vert_dof_final();
+#endif
+} \ No newline at end of file
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
index 6c4bf3bb7a0..1dc49b52be1 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
@@ -1,11 +1,3 @@
-vec3 calculate_view_space_normal(in vec3 viewposition)
-{
- vec3 normal = cross(normalize(dFdx(viewposition)),
- normalize(dFdy(viewposition)));
- normalize(normal);
- return normal;
-}
-
/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer
* we change the factors from the article to fit the OpennGL model. */
#ifdef PERSP_MATRIX
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 5e2512b6a46..494a74dcdf8 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -15,7 +15,7 @@ varying vec4 uvcoordsvar;
/* ssao_params.x : pixel scale for the ssao radious */
/* ssao_params.y : factor for the ssao darkening */
uniform vec4 ssao_params;
-uniform vec4 ssao_sample_params;
+uniform vec3 ssao_sample_params;
uniform vec4 ssao_color;
/* store the view space vectors for the corners of the view frustum here.
@@ -23,10 +23,18 @@ uniform vec4 ssao_color;
* see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
uniform vec4 viewvecs[3];
+vec3 calculate_view_space_normal(in vec3 viewposition)
+{
+ vec3 normal = cross(normalize(dFdx(viewposition)),
+ ssao_params.w * normalize(dFdy(viewposition)));
+ normalize(normal);
+ return normal;
+}
+
float calculate_ssao_factor(float depth)
{
/* take the normalized ray direction here */
- vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.zw).rg;
+ vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg;
vec2 rotY = vec2(-rotX.y, rotX.x);
/* occlusion is zero in full depth */
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 945b7ef303f..8edffe787eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -698,22 +698,7 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol = col1;
-
- if(col2.r > 0.5)
- outcol.r= col1.r + fac*(2.0*(col2.r - 0.5));
- else
- outcol.r= col1.r + fac*(2.0*(col2.r) - 1.0);
-
- if(col2.g > 0.5)
- outcol.g= col1.g + fac*(2.0*(col2.g - 0.5));
- else
- outcol.g= col1.g + fac*(2.0*(col2.g) - 1.0);
-
- if(col2.b > 0.5)
- outcol.b= col1.b + fac*(2.0*(col2.b - 0.5));
- else
- outcol.b= col1.b + fac*(2.0*(col2.b) - 1.0);
+ outcol = col1 + fac*(2.0*(col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
@@ -2114,18 +2099,23 @@ void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outco
outcol = linfac*(1.0 - exp(col*logfac));
}
-void shade_mist_factor(vec3 co, float miststa, float mistdist, float misttype, float misi, out float outfac)
+void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac)
{
- float fac, zcor;
+ if(enable == 1.0) {
+ float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
-
- fac = clamp((zcor-miststa)/mistdist, 0.0, 1.0);
- if(misttype == 0.0) fac *= fac;
- else if(misttype == 1.0);
- else fac = sqrt(fac);
+ zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
+
+ fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
+ if(misttype == 0.0) fac *= fac;
+ else if(misttype == 1.0);
+ else fac = sqrt(fac);
- outfac = 1.0 - (1.0-fac)*(1.0-misi);
+ outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
+ }
+ else {
+ outfac = 0.0;
+ }
}
void shade_world_mix(vec3 hor, vec4 col, out vec4 outcol)
diff --git a/source/blender/ikplugin/BIK_api.h b/source/blender/ikplugin/BIK_api.h
index 95b1dafd129..177be074897 100644
--- a/source/blender/ikplugin/BIK_api.h
+++ b/source/blender/ikplugin/BIK_api.h
@@ -41,7 +41,6 @@ extern "C" {
struct Object;
struct bPoseChannel;
struct bPose;
-struct bArmature;
struct Scene;
struct bConstraint;
diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt
index 0a0e0e664b4..8991e113410 100644
--- a/source/blender/ikplugin/CMakeLists.txt
+++ b/source/blender/ikplugin/CMakeLists.txt
@@ -23,6 +23,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+remove_extra_strict_flags()
+
set(INC
.
../blenkernel
@@ -59,7 +61,7 @@ if(WITH_IK_ITASC)
../../../intern/itasc
)
list(APPEND INC_SYS
- ../../../extern/Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
list(APPEND SRC
intern/itasc_plugin.cpp
diff --git a/source/blender/ikplugin/intern/ikplugin_api.h b/source/blender/ikplugin/intern/ikplugin_api.h
index 53d9da8e614..cd32bf26242 100644
--- a/source/blender/ikplugin/intern/ikplugin_api.h
+++ b/source/blender/ikplugin/intern/ikplugin_api.h
@@ -40,7 +40,6 @@ extern "C" {
struct Object;
struct bPoseChannel;
-struct bArmature;
struct Scene;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index afff97a8409..d4814a4e3a2 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -89,8 +89,7 @@ struct IK_Target;
typedef void (*ErrorCallback)(const iTaSC::ConstraintValues *values, unsigned int nvalues, IK_Target *iktarget);
// one structure for each target in the scene
-struct IK_Target
-{
+struct IK_Target {
struct Scene *blscene;
iTaSC::MovingFrame* target;
iTaSC::ConstraintSet* constraint;
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index e8977913948..bdd8230a6ff 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -62,9 +62,11 @@ set(SRC
intern/rectop.c
intern/rotate.c
intern/scaling.c
+ intern/stereoimbuf.c
intern/targa.c
intern/thumbs.c
intern/thumbs_blend.c
+ intern/thumbs_font.c
intern/util.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 262e87bedf5..59df8334099 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -47,10 +47,6 @@ struct ColormanageProcessor;
struct EnumPropertyItem;
struct ImBuf;
struct Main;
-struct rcti;
-struct PartialBufferUpdateContext;
-struct wmWindow;
-struct Scene;
struct ImageFormatData;
struct ColorSpace;
@@ -71,6 +67,9 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *
const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf);
const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf);
+float IMB_colormanagement_get_luminance(const float rgb[3]);
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
+
/* ** Color space transformation functions ** */
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 447a14b95c3..2a976092fd3 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -38,21 +38,21 @@
* \page IMB Imbuf module external interface
*
*
- * \section about About the IMB module
+ * \section imb_about About the IMB module
*
* External interface of the IMage Buffer module. This module offers
* import/export of several graphical file formats. It offers the
* ImBuf type as a common structure to refer to different graphical
* file formats, and to enable a uniform way of handling them.
*
- * \section issues Known issues with IMB
+ * \section imb_issues Known issues with IMB
*
* - imbuf is written in C.
* - Endianness issues are dealt with internally.
* - File I/O must be done externally. The module uses FILE*'s to
* direct input/output.
*
- * \section dependencies Dependencies
+ * \section imb_dependencies Dependencies
*
* IMB needs:
* - \ref DNA module
@@ -89,6 +89,13 @@ struct ColorManagedDisplay;
struct GSet;
/**
*
+ * \attention defined in DNA_scene_types.h
+ */
+struct ImageFormatData;
+struct Stereo3dFormat;
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_init(void);
@@ -240,6 +247,7 @@ typedef enum IMB_Proxy_Size {
/* defaults to BL_proxy within the directory of the animation */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
+void IMB_anim_get_fname(struct anim *anim, char *file, int size);
int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc,
int position);
@@ -271,17 +279,17 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc);
* and frs_sec and frs_sec_base untouched if none available!)
*/
bool IMB_anim_get_fps(struct anim *anim,
- short *frs_sec, float *frs_sec_base);
+ short *frs_sec, float *frs_sec_base, bool no_av_base);
/**
*
* \attention Defined in anim_movie.c
*/
struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE]);
+void IMB_suffix_anim(struct anim *anim, const char *suffix);
void IMB_close_anim(struct anim *anim);
void IMB_close_anim_proxies(struct anim *anim);
-
/**
*
* \attention Defined in anim_movie.c
@@ -376,6 +384,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
short IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
+struct ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -398,6 +407,12 @@ int imb_get_anim_type(const char *name);
/**
*
+ * \attention Defined in util.c
+ */
+bool IMB_isfloat(struct ImBuf *ibuf);
+
+/**
+ *
* \attention Defined in divers.c
*/
void IMB_de_interlace(struct ImBuf *ibuf);
@@ -452,6 +467,7 @@ void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float
void bicubic_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void nearest_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
+void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void bilinear_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
@@ -532,8 +548,21 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
const float col[4], struct ColorManagedDisplay *display,
int x1, int y1, int x2, int y2);
-/* defined in metadata.c */
+/**
+ *
+ * \attention Defined in metadata.c
+ */
+/** read the field from the image info into the field
+ * \param img - the ImBuf that contains the image data
+ * \param key - the key of the field
+ * \param value - the data in the field, first one found with key is returned,
+ * memory has to be allocated by user.
+ * \param len - length of value buffer allocated by user.
+ * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
+ */
+bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field);
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb);
/* exported for image tools in blender, to quickly allocate 32 bits rect */
bool imb_addrectImBuf(struct ImBuf *ibuf);
@@ -556,5 +585,27 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
-#endif
+/**
+ *
+ * \attention defined in stereoimbuf.c
+ */
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height);
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height);
+int *IMB_stereo3d_from_rect(
+ struct ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right);
+float *IMB_stereo3d_from_rectf(
+ struct ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right);
+struct ImBuf *IMB_stereo3d_ImBuf(
+ struct ImageFormatData *im_format,
+ struct ImBuf *ibuf_left, struct ImBuf *ibuf_right);
+void IMB_ImBufFromStereo3d(
+ struct Stereo3dFormat *s3d, struct ImBuf *ibuf_stereo,
+ struct ImBuf **r_ibuf_left, struct ImBuf **r_ibuf_right);
+#endif
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9e7201f53b4..862c587f75b 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -110,7 +110,7 @@ typedef struct ImBuf {
int index; /* reference index for ImBuf lists */
int userflags; /* used to set imbuf to dirty and other stuff */
struct IDProperty *metadata; /* image metadata */
- void *userdata; /* temporary storage, only used by baking at the moment */
+ void *userdata; /* temporary storage */
/* file information */
int ftype; /* file type we are going to save as */
@@ -172,6 +172,8 @@ typedef struct ImBuf {
#define IB_alphamode_premul (1 << 12) /* indicates whether image on disk have premul alpha */
#define IB_alphamode_detect (1 << 13) /* if this flag is set, alpha mode would be guessed from file */
#define IB_ignore_alpha (1 << 14) /* ignore alpha on load and substitude it with 1.0f */
+#define IB_thumbnail (1 << 15)
+#define IB_multiview (1 << 16)
/*
* The bit flag is stored in the ImBuf.ftype variable.
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index 9fc075e4e8b..f2f75973bcd 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -54,13 +54,19 @@ typedef enum ThumbSize {
typedef enum ThumbSource {
THB_SOURCE_IMAGE,
THB_SOURCE_MOVIE,
- THB_SOURCE_BLEND
+ THB_SOURCE_BLEND,
+ THB_SOURCE_FONT,
} ThumbSource;
/* don't generate thumbs for images bigger then this (100mb) */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
-// IB_metadata
+#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
+
+/* Note this can also be used as versionning system,
+ * to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
+ * Only used by fonts so far. */
+#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
/* create thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *ibuf);
@@ -78,8 +84,12 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
void IMB_thumb_makedirs(void);
/* special function for loading a thumbnail embedded into a blend file */
-ImBuf *IMB_loadblend_thumb(const char *path);
-void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect);
+ImBuf *IMB_thumb_load_blend(const char *path);
+void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float aspect);
+
+/* special function for previewing fonts */
+ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
+bool IMB_thumb_load_font_get_hash(char *r_hash);
#ifdef __cplusplus
}
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index ed349e8f7eb..690ec813407 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -79,11 +79,7 @@
#endif
#ifdef WITH_REDCODE
-# ifdef _WIN32 /* on windows we use the one in extern instead */
-# include "libredcode/format.h"
-# else
-# include "libredcode/format.h"
-# endif
+# include "libredcode/format.h"
#endif
#include "IMB_imbuf_types.h"
@@ -194,6 +190,7 @@ struct anim {
struct anim_index *curr_idx[IMB_TC_MAX_SLOT];
char colorspace[64];
+ char suffix[64]; /* MAX_NAME - multiview */
};
#endif
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 9327c15c415..332878b6067 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -40,7 +40,7 @@ typedef struct ImFileType {
int (*is_a)(unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
struct ImBuf *(*load)(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
struct ImBuf *(*load_filepath)(const char *name, int flags, char colorspace[IM_MAX_SPACE]);
int (*save)(struct ImBuf *ibuf, const char *name, int flags);
@@ -51,8 +51,8 @@ typedef struct ImFileType {
int default_save_role;
} ImFileType;
-extern ImFileType IMB_FILE_TYPES[];
-extern ImFileType *IMB_FILE_TYPES_LAST;
+extern const ImFileType IMB_FILE_TYPES[];
+extern const ImFileType *IMB_FILE_TYPES_LAST;
void imb_filetypes_init(void);
void imb_filetypes_exit(void);
@@ -88,7 +88,7 @@ int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags);
/* jpeg */
int imb_is_a_jpeg(unsigned char *mem);
int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags);
-struct ImBuf *imb_load_jpeg (unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_load_jpeg(unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
/* bmp */
int imb_is_a_bmp(unsigned char *buf);
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h
index 5d4a0028ee1..bc0b2c70ecb 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/intern/IMB_metadata.h
@@ -47,16 +47,6 @@ struct ImBuf;
/* free blender ImMetaData struct */
void IMB_metadata_free(struct ImBuf *img);
-/** read the field from the image info into the field
- * \param img - the ImBuf that contains the image data
- * \param key - the key of the field
- * \param value - the data in the field, first one found with key is returned,
- * memory has to be allocated by user.
- * \param len - length of value buffer allocated by user.
- * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
- */
-bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
-
/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create
* before calling this function.
* \param img - the ImBuf that contains the image data
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index b28d19e3e15..79f869968d3 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -210,6 +210,8 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf)
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
+
IMB_freeImBuf(ibuf);
return rval;
@@ -465,10 +467,10 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
if (ibuf2 == NULL) return NULL;
if (flags & IB_rect)
- memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int));
+ memcpy(ibuf2->rect, ibuf1->rect, ((size_t)x) * y * sizeof(int));
if (flags & IB_rectfloat)
- memcpy(ibuf2->rect_float, ibuf1->rect_float, ibuf1->channels * x * y * sizeof(float));
+ memcpy(ibuf2->rect_float, ibuf1->rect_float, ((size_t)ibuf1->channels) * x * y * sizeof(float));
if (ibuf1->encodedbuffer) {
ibuf2->encodedbuffersize = ibuf1->encodedbuffersize;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index ffdecb793aa..e2d56d29726 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -99,13 +99,8 @@
#endif //WITH_FFMPEG
#ifdef WITH_REDCODE
-#ifdef _WIN32 /* on windows we use the ones in extern instead */
-#include "libredcode/format.h"
-#include "libredcode/codec.h"
-#else
-#include "libredcode/format.h"
-#include "libredcode/codec.h"
-#endif
+# include "libredcode/format.h"
+# include "libredcode/codec.h"
#endif
#include "IMB_colormanagement.h"
@@ -271,6 +266,8 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
{
struct anim *anim;
+ BLI_assert(!BLI_path_is_rel(name));
+
anim = (struct anim *)MEM_callocN(sizeof(struct anim), "anim struct");
if (anim != NULL) {
if (colorspace) {
@@ -288,6 +285,11 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
return(anim);
}
+void IMB_suffix_anim(struct anim *anim, const char *suffix)
+{
+ BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
+}
+
#ifdef WITH_AVI
static int startavi(struct anim *anim)
{
@@ -1422,11 +1424,18 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
}
bool IMB_anim_get_fps(struct anim *anim,
- short *frs_sec, float *frs_sec_base)
+ short *frs_sec, float *frs_sec_base, bool no_av_base)
{
if (anim->frs_sec) {
*frs_sec = anim->frs_sec;
*frs_sec_base = anim->frs_sec_base;
+#ifdef WITH_FFMPEG
+ if (no_av_base) {
+ *frs_sec_base /= AV_TIME_BASE;
+ }
+#else
+ UNUSED_VARS(no_av_base);
+#endif
return true;
}
return false;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 19e655a0b3d..298e2da965f 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -136,7 +136,7 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
- bmp = mem + LITTLE_LONG(*(int*)(mem + 10));
+ bmp = mem + LITTLE_LONG(*(int *)(mem + 10));
if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 0e71206517e..fbce508af17 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -307,7 +307,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
printf(" Transfer characteristics: %d\n", cineon->element[i].transfer);
printf(" Packing: %d\n", cineon->element[i].packing);
printf(" Descriptor: %d\n", cineon->element[i].descriptor);
- printf(" Data offset: %u\n", cineon->element[i].dataOffset);
+ printf(" Data offset: %d\n", cineon->element[i].dataOffset);
printf(" Reference low data: %u\n", cineon->element[i].refLowData);
printf(" Reference low quantity: %f\n", cineon->element[i].refLowQuantity);
printf(" Reference high data: %u\n", cineon->element[i].refHighData);
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 23e5517bb09..562bdecb842 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -366,7 +366,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
printf(" Transfer characteristics: %d\n", dpx->element[i].transfer);
printf(" Packing: %d\n", dpx->element[i].packing);
printf(" Descriptor: %d\n", dpx->element[i].descriptor);
- printf(" Data offset: %u\n", dpx->element[i].dataOffset);
+ printf(" Data offset: %d\n", dpx->element[i].dataOffset);
printf(" Reference low data: %u\n", dpx->element[i].refLowData);
printf(" Reference low quantity: %f\n", dpx->element[i].refLowQuantity);
printf(" Reference high data: %u\n", dpx->element[i].refHighData);
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
index 1500f4282e5..5ec0a87890c 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.c
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -623,7 +623,7 @@ static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logEl
for (y = 0; y < logImage->height; y++) {
/* 8 bits are 32-bits padded so we need to seek at each row */
if (logimage_fseek(logImage, logElement.dataOffset + y * rowLength, SEEK_SET) != 0) {
- if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * rowLength);
+ if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * (int)rowLength);
return 1;
}
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 6b1435817d2..389e88a24de 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -52,8 +52,7 @@ enum format {
format_Cineon
};
-typedef struct LogImageElement
-{
+typedef struct LogImageElement {
int depth;
int bitsPerSample;
int dataOffset;
@@ -67,8 +66,7 @@ typedef struct LogImageElement
float maxValue; /* = 2^bitsPerSample - 1 (used internally, doesn't come from the file header) */
} LogImageElement;
-typedef struct LogImageFile
-{
+typedef struct LogImageFile {
/* specified in header */
int width;
int height;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 95e166b2f8b..a61204ea850 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -90,6 +90,11 @@ static int global_tot_display = 0;
static int global_tot_view = 0;
static int global_tot_looks = 0;
+/* Set to ITU-BT.709 / sRGB primaries weight. Brute force stupid, but only
+ * option with no colormanagement in place.
+ */
+static float luma_coefficients[3] = { 0.2126f, 0.7152f, 0.0722f };
+
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
* LOCK_COLORMANAGE can not be used since this mutex could be needed to
@@ -545,6 +550,9 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
colormanage_look_add(name, process_space, false);
}
+
+ /* Load luminance coefficients. */
+ OCIO_configGetDefaultLumaCoefs(config, luma_coefficients);
}
static void colormanage_free_config(void)
@@ -1222,6 +1230,34 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
return ibuf->rect_colorspace->name;
}
+/* Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
+
+float IMB_colormanagement_get_luminance(const float rgb[3])
+{
+ return dot_v3v3(luma_coefficients, rgb);
+}
+
+/* Byte equivalent of IMB_colormanagement_get_luminance(). */
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
+{
+ float rgbf[3];
+ float val;
+
+ rgb_uchar_to_float(rgbf, rgb);
+ val = dot_v3v3(luma_coefficients, rgbf);
+
+ return FTOCHAR(val);
+}
+
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
@@ -1270,8 +1306,8 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
float dither = ibuf->dither;
bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
- int offset = channels * start_line * ibuf->x;
- int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x;
+ size_t offset = ((size_t)channels) * start_line * ibuf->x;
+ size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
memset(handle, 0, sizeof(DisplayBufferThread));
@@ -1308,7 +1344,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
int channels = handle->channels;
int width = handle->width;
- int buffer_size = channels * width * height;
+ size_t buffer_size = ((size_t)channels) * width * height;
bool is_data = handle->is_data;
bool is_data_display = handle->cm_processor->is_data_result;
@@ -1321,11 +1357,12 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
float *fp;
unsigned char *cp;
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
/* first convert byte buffer to float, keep in image space */
for (i = 0, fp = linear_buffer, cp = byte_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels, cp += channels)
{
if (channels == 3) {
@@ -1404,7 +1441,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
else {
bool is_straight_alpha, predivide;
- float *linear_buffer = MEM_mallocN(channels * width * height * sizeof(float),
+ float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
"color conversion linear buffer");
display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
@@ -1431,14 +1468,15 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
if (display_buffer) {
- memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
+ memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
if (is_straight_alpha && channels == 4) {
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
float *fp;
for (i = 0, fp = display_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels)
{
straight_to_premul_v4(fp);
@@ -1566,7 +1604,7 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
int width = init_data->width;
bool predivide = init_data->predivide;
- int offset = channels * start_line * width;
+ size_t offset = ((size_t)channels) * start_line * width;
memset(handle, 0, sizeof(ProcessorTransformThread));
@@ -1751,8 +1789,10 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in
if (processor) {
OCIO_PackedImageDesc *img;
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(processor, img);
@@ -1912,7 +1952,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
if (do_colormanagement) {
bool make_byte = false;
- ImFileType *type;
+ const ImFileType *type;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
@@ -1954,7 +1994,7 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char
const ColorManagedDisplaySettings *display_settings)
{
ColormanageProcessor *cm_processor;
- size_t float_buffer_size = width * height * channels * sizeof(float);
+ 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");
memcpy(display_buffer_float, buffer, float_buffer_size);
@@ -1979,7 +2019,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
const ColorManagedDisplaySettings *display_settings, void **cache_handle)
{
unsigned char *display_buffer;
- int buffer_size;
+ size_t buffer_size;
ColormanageCacheViewSettings cache_view_settings;
ColormanageCacheDisplaySettings cache_display_settings;
ColorManagedViewSettings default_view_settings;
@@ -2047,7 +2087,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
return display_buffer;
}
- buffer_size = DISPLAY_BUFFER_CHANNELS * ibuf->x * ibuf->y * sizeof(char);
+ buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
@@ -2077,8 +2117,8 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *li
float *buffer;
ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer");
- memcpy(buffer, linear_buffer, channels * width * height * sizeof(float));
+ buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float), "display transform temp buffer");
+ memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
@@ -2421,7 +2461,7 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->save && type->ftype(type, ibuf)) {
@@ -2622,14 +2662,14 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
if (!cm_processor)
channels = 4;
- display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither");
+ display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float), "display buffer for dither");
}
if (cm_processor) {
for (y = ymin; y < ymax; y++) {
for (x = xmin; x < xmax; x++) {
- int display_index = (y * display_stride + x) * 4;
- int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
+ size_t display_index = ((size_t)y * display_stride + x) * 4;
+ size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
float pixel[4];
if (linear_buffer) {
@@ -2658,7 +2698,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int index = ((y - ymin) * width + (x - xmin)) * channels;
+ size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
if (channels == 4) {
copy_v4_v4(display_buffer_float + index, pixel);
@@ -2701,8 +2741,8 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
int i;
for (i = ymin; i < ymax; i++) {
- int byte_offset = (linear_stride * i + xmin) * 4;
- int display_offset = (display_stride * i + xmin) * 4;
+ size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
+ size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
memcpy(display_buffer + display_offset, byte_buffer + byte_offset, 4 * sizeof(char) * width);
}
@@ -2710,7 +2750,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int display_index = (ymin * display_stride + xmin) * channels;
+ size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither,
IB_PROFILE_SRGB, IB_PROFILE_SRGB, true, width, height, display_stride, width);
@@ -2797,8 +2837,8 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
if (copy_display_to_byte_buffer && (unsigned char *) ibuf->rect != display_buffer) {
int y;
for (y = ymin; y < ymax; y++) {
- int index = y * buffer_width * 4;
- memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4);
+ size_t index = (size_t)y * buffer_width * 4;
+ memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4);
}
}
}
@@ -2923,7 +2963,7 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- float *pixel = buffer + channels * (y * width + x);
+ float *pixel = buffer + channels * (((size_t)y) * width + x);
curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
}
@@ -2934,8 +2974,10 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
OCIO_PackedImageDesc *img;
/* apply OCIO processor */
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(cm_processor->processor, img);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 7e5a1e504b8..6aae9c9817c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -64,8 +64,7 @@
#include <Stream.h>
/// DXT1 block.
-struct BlockDXT1
-{
+struct BlockDXT1 {
Color16 col0;
Color16 col1;
union {
@@ -98,8 +97,7 @@ inline bool BlockDXT1::isFourColorMode() const
/// DXT3 alpha block with explicit alpha.
-struct AlphaBlockDXT3
-{
+struct AlphaBlockDXT3 {
union {
struct {
uint alpha0 : 4;
@@ -130,8 +128,7 @@ struct AlphaBlockDXT3
/// DXT3 block.
-struct BlockDXT3
-{
+struct BlockDXT3 {
AlphaBlockDXT3 alpha;
BlockDXT1 color;
@@ -144,8 +141,7 @@ struct BlockDXT3
/// DXT5 alpha block.
-struct AlphaBlockDXT5
-{
+struct AlphaBlockDXT5 {
// uint64 unions do not compile on all platforms
#if 0
union {
@@ -208,8 +204,7 @@ struct AlphaBlockDXT5
/// DXT5 block.
-struct BlockDXT5
-{
+struct BlockDXT5 {
AlphaBlockDXT5 alpha;
BlockDXT1 color;
@@ -221,8 +216,7 @@ struct BlockDXT5
};
/// ATI1 block.
-struct BlockATI1
-{
+struct BlockATI1 {
AlphaBlockDXT5 alpha;
void decodeBlock(ColorBlock * block) const;
@@ -232,8 +226,7 @@ struct BlockATI1
};
/// ATI2 block.
-struct BlockATI2
-{
+struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
@@ -244,8 +237,7 @@ struct BlockATI2
};
/// CTX1 block.
-struct BlockCTX1
-{
+struct BlockCTX1 {
uint8 col0[2];
uint8 col1[2];
union {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 730a19d84fd..8d5031aa603 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -41,8 +41,7 @@
#include <Image.h>
/// Uncompressed 4x4 color block.
-struct ColorBlock
-{
+struct ColorBlock {
ColorBlock();
ColorBlock(const uint * linearImage);
ColorBlock(const ColorBlock & block);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 028026527dc..6bf82776afe 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -60,6 +60,7 @@
#include <PixelFormat.h>
#include <stdio.h> // printf
+#include <stdlib.h> // malloc
#include <math.h> // sqrt
#include <sys/types.h>
@@ -496,8 +497,7 @@ void mem_read(Stream & mem, DDSHeader & header)
namespace
{
-struct FormatDescriptor
-{
+struct FormatDescriptor {
uint format;
uint bitcount;
uint rmask;
@@ -1148,7 +1148,7 @@ void* DirectDrawSurface::readData(uint &rsize)
uint size = stream.size - header_size;
rsize = size;
- unsigned char *data = new unsigned char[size];
+ unsigned char *data = (unsigned char *)malloc(sizeof(*data) * size);
stream.seek(header_size);
mem_read(stream, data, size);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 3d308ba1ff1..44c27a98c1d 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -63,8 +63,7 @@
#include <ColorBlock.h>
#include <Image.h>
-struct DDSPixelFormat
-{
+struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
@@ -75,8 +74,7 @@ struct DDSPixelFormat
uint amask;
};
-struct DDSCaps
-{
+struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
@@ -84,8 +82,7 @@ struct DDSCaps
};
/// DDS file header for DX10.
-struct DDSHeader10
-{
+struct DDSHeader10 {
uint dxgiFormat;
uint resourceDimension;
uint miscFlag;
@@ -94,8 +91,7 @@ struct DDSHeader10
};
/// DDS file header.
-struct DDSHeader
-{
+struct DDSHeader {
uint fourcc;
uint size;
uint flags;
diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h
index a1ac49b58da..6557fb4f063 100644
--- a/source/blender/imbuf/intern/dds/Stream.h
+++ b/source/blender/imbuf/intern/dds/Stream.h
@@ -30,8 +30,7 @@
#ifndef __STREAM_H__
#define __STREAM_H__
-struct Stream
-{
+struct Stream {
unsigned char *mem; // location in memory
unsigned int size; // size
unsigned int pos; // current position
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index a6d53ffac96..45d9fa2ac59 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -47,7 +47,7 @@ extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-int imb_save_dds(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
{
return(0); /* todo: finish this function */
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 65abf22ff2c..455b78bce4d 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -184,16 +184,16 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]);
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -221,8 +221,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
float straight[4];
@@ -334,8 +334,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -343,8 +343,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -355,8 +355,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
float straight[4];
@@ -408,7 +408,7 @@ void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
/* RGBA input */
for (y = 0; y < height; y++) {
const uchar *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -460,8 +460,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = from[0];
@@ -470,8 +470,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -499,12 +499,12 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
- memcpy(to, from, sizeof(float) * 4 * width);
+ memcpy(to, from, sizeof(float) * ((size_t)4) * width);
}
else if (profile_to == IB_PROFILE_LINEAR_RGB) {
/* convert to sRGB to linear */
@@ -541,8 +541,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -552,8 +552,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -566,8 +566,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 4, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -590,8 +590,8 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
/* always RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
@@ -690,8 +690,8 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
imb_addrectImBuf(ibuf);
/* do conversion */
- rect_float = ibuf->rect_float + (x + y * ibuf->x) * ibuf->channels;
- rect_byte = (uchar *)ibuf->rect + (x + y * ibuf->x) * 4;
+ rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
+ rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
if (is_data) {
/* exception for non-color data, just copy float */
@@ -734,9 +734,9 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- int size;
+ size_t size;
- size = ibuf->x * ibuf->y;
+ size = ((size_t)ibuf->x) * ibuf->y;
size = size * 4 * sizeof(float);
ibuf->channels = 4;
@@ -771,22 +771,22 @@ void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
uchar *rct = (uchar *)ibuf->rect;
- int i;
+ size_t i;
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4)
- rct_fl[0] = rct_fl[1] = rct_fl[2] = rgb_to_grayscale(rct_fl);
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4)
+ rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
if (rct) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4)
- rct[0] = rct[1] = rct[2] = rgb_to_grayscale_byte(rct);
+ for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4)
+ rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
void IMB_buffer_float_clamp(float *buf, int width, int height)
{
- int i, total = width * height * 4;
+ size_t i, total = ((size_t)width) * height * 4;
for (i = 0; i < total; i++) {
buf[i] = min_ff(1.0, buf[i]);
}
@@ -794,7 +794,7 @@ void IMB_buffer_float_clamp(float *buf, int width, int height)
void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
premul_to_straight_v4(fp);
@@ -804,7 +804,7 @@ void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
void IMB_buffer_float_premultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
straight_to_premul_v4(fp);
@@ -816,14 +816,14 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height)
void IMB_saturation(ImBuf *ibuf, float sat)
{
- int i;
+ size_t i;
unsigned char *rct = (unsigned char *)ibuf->rect;
float *rct_fl = ibuf->rect_float;
float hsv[3];
if (rct) {
float rgb[3];
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -832,7 +832,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index c6e358dd3d2..e58cda07ecf 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -51,17 +51,17 @@
#include "quicktime_import.h"
#endif
-static int imb_ftype_default(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
{
return (ibuf->ftype & type->filetype);
}
-static int imb_ftype_iris(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMAGIC);
}
-ImFileType IMB_FILE_TYPES[] = {
+const ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, imb_is_a_jpeg, NULL, imb_ftype_default, imb_load_jpeg, NULL, imb_savejpeg, NULL, 0, JPG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_png, NULL, imb_ftype_default, imb_loadpng, NULL, imb_savepng, NULL, 0, PNG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_bmp, NULL, imb_ftype_default, imb_bmp_decode, NULL, imb_savebmp, NULL, 0, BMP, COLOR_ROLE_DEFAULT_BYTE},
@@ -92,11 +92,11 @@ ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}
};
-ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
+const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
void imb_filetypes_init(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->init)
@@ -109,7 +109,7 @@ void imb_filetypes_init(void)
void imb_filetypes_exit(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->exit)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 352e230068b..7adb2c7cc1d 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -526,7 +526,7 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
hbuf = ibuf->mipmap[curmap];
hbuf->miplevel = curmap + 1;
- if (hbuf->x <= 2 && hbuf->y <= 2)
+ if (hbuf->x < 2 && hbuf->y < 2)
break;
curmap++;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 8234b01992b..d44f0dc86f4 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -51,7 +51,7 @@
/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
- int size;
+ size_t size;
unsigned char rt, *cp = (unsigned char *)ibuf->rect;
float rtf, *cpf = ibuf->rect_float;
@@ -86,7 +86,7 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
- int offset = ibuf->x * y * 4 + 4 * x;
+ size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
if (ibuf->rect)
*outI = (unsigned char *)ibuf->rect + offset;
@@ -172,10 +172,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
if (outF) {
/* sample including outside of edges of image */
- row1 = in->rect_float + in->x * y1 * 4 + 4 * x1;
- row2 = in->rect_float + in->x * y2 * 4 + 4 * x1;
- row3 = in->rect_float + in->x * y1 * 4 + 4 * x2;
- row4 = in->rect_float + in->x * y2 * 4 + 4 * x2;
+ row1 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x2;
outF[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
outF[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
@@ -190,10 +190,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
}
if (outI) {
/* sample including outside of edges of image */
- row1I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
- row2I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x1;
- row3I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x2;
- row4I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x2;
+ row1I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x2;
/* need to add 0.5 to avoid rounding down (causes darken with the smear brush)
* tested with white images and this should not wrap back to zero */
@@ -256,14 +256,14 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
else {
- dataI = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outI) {
outI[0] = dataI[0];
outI[1] = dataI[1];
outI[2] = dataI[2];
outI[3] = dataI[3];
}
- dataF = in->rect_float + in->x * y1 * 4 + 4 * x1;
+ dataF = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outF) {
outF[0] = dataF[0];
outF[1] = dataF[1];
@@ -273,6 +273,41 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
+
+void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+{
+ const float *dataF;
+ unsigned char *dataI;
+ int y, x;
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+
+ x = (int) floor(u);
+ y = (int) floor(v);
+
+ x = x % in->x;
+ y = y % in->y;
+
+ /* wrap interpolation pixels - main difference from nearest_interpolation_color */
+ if (x < 0) x += in->x;
+ if (y < 0) y += in->y;
+
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outI) {
+ outI[0] = dataI[0];
+ outI[1] = dataI[1];
+ outI[2] = dataI[2];
+ outI[3] = dataI[3];
+ }
+ dataF = in->rect_float + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outF) {
+ outF[0] = dataF[0];
+ outF[1] = dataF[1];
+ outF[2] = dataF[2];
+ outF[3] = dataF[3];
+ }
+}
+
void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout)
{
unsigned char *outI = NULL;
@@ -343,7 +378,7 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
float *fp = rect_float;
while (a--) {
@@ -366,7 +401,7 @@ void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
unsigned char *cp = rect;
while (a--) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index d0281744830..ac57b095800 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -41,7 +41,6 @@
#include "IMB_anim.h"
#include "imbuf.h"
-#include "MEM_guardedalloc.h"
#include "BKE_global.h"
#ifdef WITH_AVI
@@ -374,6 +373,13 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l
}
}
+void IMB_anim_get_fname(struct anim *anim, char *file, int size)
+{
+ char fname[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname));
+ BLI_strncpy(file, fname, size);
+}
+
static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
char *fname, bool temp)
{
@@ -381,8 +387,8 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
int i = IMB_proxy_size_to_array_index(preview_size);
char proxy_name[256];
- char proxy_temp_name[256];
char stream_suffix[20];
+ const char *name = (temp) ? "proxy_%d%s_part.avi" : "proxy_%d%s.avi";
stream_suffix[0] = 0;
@@ -390,15 +396,12 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
}
- BLI_snprintf(proxy_name, sizeof(proxy_name), "proxy_%d%s.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
- BLI_snprintf(proxy_temp_name, sizeof(proxy_temp_name), "proxy_%d%s_part.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
+ BLI_snprintf(proxy_name, sizeof(proxy_name), name,
+ (int) (proxy_fac[i] * 100), stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
- temp ? proxy_temp_name : proxy_name);
+ BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
}
static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
@@ -407,10 +410,10 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
const char *index_names[] = {
- "record_run%s.blen_tc",
- "free_run%s.blen_tc",
- "interp_free_run%s.blen_tc",
- "record_run_no_gaps%s.blen_tc"
+ "record_run%s%s.blen_tc",
+ "free_run%s%s.blen_tc",
+ "interp_free_run%s%s.blen_tc",
+ "record_run_no_gaps%s%s.blen_tc"
};
char stream_suffix[20];
@@ -422,7 +425,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
- BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
+ BLI_snprintf(index_name, 256, index_names[i], stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
@@ -1002,7 +1005,7 @@ static AviMovie *alloc_proxy_output_avi(
* but sane defaults help anyways...*/
float frs_sec_base = 1.0;
- IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
+ IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base, false);
x = width;
y = height;
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 8cb5070dd62..134bbe88f15 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -79,6 +79,13 @@ bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, con
return retval;
}
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
+{
+ if (simb->metadata) {
+ dimb->metadata = IDP_CopyProperty(simb->metadata);
+ }
+}
+
bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value)
{
IDProperty *prop;
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 29bb35986e8..4b49076dcd6 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -147,8 +147,8 @@ static void check_unused_keys(MovieCache *cache)
BLI_ghashIterator_init(&gh_iter, cache->hash);
while (!BLI_ghashIterator_done(&gh_iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
+ const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
bool remove;
BLI_ghashIterator_step(&gh_iter);
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index 5fb8f11602e..c873fa3f32d 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
if(WITH_OPENIMAGEIO)
list(APPEND INC_SYS
${OPENIMAGEIO_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
)
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 6e3f97a4902..7728183d3b6 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -182,7 +182,7 @@ int imb_is_a_photoshop(const char *filename)
return BLI_testextensie_array(filename, photoshop_extension);
}
-int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
{
if (flags & IB_mem) {
std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory"
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 45eae89ad9d..44b7fbf6315 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -63,6 +63,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "BLI_threads.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -92,9 +93,32 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include <ImfStringAttribute.h>
#include <ImfStandardAttributes.h>
+/* multiview/multipart */
+#include <ImfMultiView.h>
+#include <ImfMultiPartInputFile.h>
+#include <ImfInputPart.h>
+#include <ImfOutputPart.h>
+#include <ImfMultiPartOutputFile.h>
+#include <ImfTiledOutputPart.h>
+#include <ImfPartType.h>
+#include <ImfPartHelper.h>
+
using namespace Imf;
using namespace Imath;
+extern "C"
+{
+/* prototype */
+static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
+static bool exr_has_multiview(MultiPartInputFile& file);
+static bool exr_has_multipart_file(MultiPartInputFile& file);
+static bool exr_has_alpha(MultiPartInputFile& file);
+static bool exr_has_zbuffer(MultiPartInputFile& file);
+static void exr_printf(const char *__restrict format, ...);
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
+}
+
/* Memory Input Stream */
class Mem_IStream : public Imf::IStream
@@ -340,13 +364,28 @@ static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
}
-static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
+static void openexr_header_metadata_callback(void *data, const char *propname, const char *prop)
+{
+ Header *header = (Header *)data;
+ header->insert(propname, StringAttribute(prop));
+}
+
+
+static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -355,13 +394,22 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(HALF));
- header.channels().insert("G", Channel(HALF));
- header.channels().insert("B", Channel(HALF));
- if (is_alpha)
- header.channels().insert("A", Channel(HALF));
- if (is_zbuf) // z we do as float always
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
+ if (is_zbuf) // z we do as float always
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -370,75 +418,91 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
OutputFile file(file_stream, header);
/* we store first everything in half array */
- RGBAZ *pixels = new RGBAZ[height * width];
- RGBAZ *to = pixels;
+ RGBAZ *pixels = new RGBAZ[height * width * totviews];
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
- /* indicate used buffers */
- frameBuffer.insert("R", Slice(HALF, (char *) &pixels[0].r, xstride, ystride));
- frameBuffer.insert("G", Slice(HALF, (char *) &pixels[0].g, xstride, ystride));
- frameBuffer.insert("B", Slice(HALF, (char *) &pixels[0].b, xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
- if (ibuf->rect_float) {
- float *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = ibuf->rect_float + channels * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = from[0];
- to->g = (channels >= 2) ? from[1] : from[0];
- to->b = (channels >= 3) ? from[2] : from[0];
- to->a = (channels >= 4) ? from[3] : 1.0f;
- to++; from += channels;
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+ const size_t offset = view_id * width * height;
+ RGBAZ *to = pixels + offset;
+
+ /* indicate used buffers */
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF, (char *) &pixels[offset].g, xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF, (char *) &pixels[offset].b, xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+ if (view_ibuf->rect_float) {
+ float *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = view_ibuf->rect_float + channels * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = from[0];
+ to->g = (channels >= 2) ? from[1] : from[0];
+ to->b = (channels >= 3) ? from[2] : from[0];
+ to->a = (channels >= 4) ? from[3] : 1.0f;
+ to++; from += channels;
+ }
}
}
- }
- else {
- unsigned char *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = (unsigned char *)ibuf->rect + 4 * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
- to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
- to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
- to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
- to++; from += 4;
+ else {
+ unsigned char *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = (unsigned char *)view_ibuf->rect + 4 * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
+ to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
+ to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
+ to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
+ to++; from += 4;
+ }
}
}
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
}
-// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
+ exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
delete[] pixels;
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
- return (0);
+ return false;
}
- return (1);
+ return true;
}
-static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
+static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -447,13 +511,22 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(Imf::FLOAT));
- header.channels().insert("G", Channel(Imf::FLOAT));
- header.channels().insert("B", Channel(Imf::FLOAT));
- if (is_alpha)
- header.channels().insert("A", Channel(Imf::FLOAT));
- if (is_zbuf)
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
+ if (is_zbuf)
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -463,37 +536,41 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
int xstride = sizeof(float) * channels;
int ystride = -xstride * width;
- float *rect[4] = {NULL, NULL, NULL, NULL};
- /* last scanline, stride negative */
- rect[0] = ibuf->rect_float + channels * (height - 1) * width;
- rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
- rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
- rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
-
- frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
- frameBuffer.insert("G", Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
- frameBuffer.insert("B", Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ float *rect[4] = {NULL, NULL, NULL, NULL};
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+
+ /* last scanline, stride negative */
+ rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
+ rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
+ rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
+ rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
+
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
+ }
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
-
- return (0);
+ return false;
}
- return (1);
- // printf("OpenEXR-save: Done.\n");
+ return true;
}
-
int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
{
if (flags & IB_mem) {
@@ -504,16 +581,48 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
}
if (ibuf->ftype & OPENEXR_HALF)
- return imb_save_openexr_half(ibuf, name, flags);
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else {
+ /* when no float rect, we save as half (16 bits is sufficient) */
+ if (ibuf->rect_float == NULL)
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else
+ return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
+ }
+}
+
+static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ if (flags & IB_mem) {
+ printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+ return false;
+ }
+
+ if (ibuf->ftype & OPENEXR_HALF)
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else {
/* when no float rect, we save as half (16 bits is sufficient) */
if (ibuf->rect_float == NULL)
- return imb_save_openexr_half(ibuf, name, flags);
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else
- return imb_save_openexr_float(ibuf, name, flags);
+ return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
}
}
+/* Save single-layer multiview OpenEXR
+ * If we have more multiview formats in the future, the function below could be incorporated
+ * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
+bool IMB_exr_multiview_save(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
+}
+
/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
/* naming rules:
@@ -527,30 +636,39 @@ static ListBase exrhandles = {NULL, NULL};
typedef struct ExrHandle {
struct ExrHandle *next, *prev;
+ char name[FILE_MAX];
- IFileStream *ifile_stream;
- InputFile *ifile;
+ IStream *ifile_stream;
+ MultiPartInputFile *ifile;
OFileStream *ofile_stream;
- TiledOutputFile *tofile;
+ MultiPartOutputFile *mpofile;
OutputFile *ofile;
int tilex, tiley;
int width, height;
int mipmap;
+ StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
+ int parts;
+
ListBase channels; /* flattened out, ExrChannel */
ListBase layers; /* hierarchical, pointing in end to ExrChannel */
+
+ int num_half_channels; /* used during filr save, allows faster temporary buffers allocation */
} ExrHandle;
/* flattened out channel */
typedef struct ExrChannel {
struct ExrChannel *next, *prev;
- char name[EXR_TOT_MAXNAME + 1]; /* full name of layer+pass */
+ char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */
+ struct MultiViewChannelName *m; /* struct to store all multipart channel info */
int xstride, ystride; /* step to next pixel, to next scanline */
float *rect; /* first pointer to write in */
char chan_id; /* quick lookup of channel char */
+ int view_id; /* quick lookup of channel view */
+ bool use_half_float; /* when saving use half float for file storage */
} ExrChannel;
@@ -562,6 +680,10 @@ typedef struct ExrPass {
float *rect;
struct ExrChannel *chan[EXR_PASS_MAXCHAN];
char chan_id[EXR_PASS_MAXCHAN];
+
+ char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
+ char view[EXR_VIEW_MAXNAME];
+ int view_id;
} ExrPass;
typedef struct ExrLayer {
@@ -575,40 +697,153 @@ typedef struct ExrLayer {
void *IMB_exr_get_handle(void)
{
ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ data->multiView = new StringVector();
+
BLI_addtail(&exrhandles, data);
return data;
}
+void *IMB_exr_get_handle_name(const char *name)
+{
+ ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
+
+ if (data == NULL) {
+ data = (ExrHandle *)IMB_exr_get_handle();
+ BLI_strncpy(data->name, name, strlen(name) + 1);
+ }
+ return data;
+}
+
+/* multiview functions */
+} // extern "C"
+
+extern "C"
+{
+
+void IMB_exr_add_view(void *handle, const char *name)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ data->multiView->push_back(name);
+}
+
+static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
+{
+ int count = 0;
+ for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
+ if (name == *i)
+ return count;
+ else
+ count ++;
+ }
+
+ /* no views or wrong name */
+ return -1;
+}
+
+static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
+{
+ if (exr_has_multipart_file(file) == false) {
+ if (exr_has_multiview(file)) {
+ StringVector sv = multiView(file.header(0));
+ for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
+ views.push_back(*i);
+ }
+ }
+
+ else {
+ for (int p = 0; p < file.parts(); p++) {
+ std::string view = "";
+ if (file.header(p).hasView())
+ view = file.header(p).view();
+
+ if (imb_exr_get_multiView_id(views, view) == -1)
+ views.push_back(view);
+ }
+ }
+}
+
+/* Multilayer Blender files have the view name in all the passes (even the default view one) */
+static const char *imb_exr_insert_view_name(const char *passname, const char *viewname)
+{
+ if (viewname == NULL || viewname[0] == '\0')
+ return passname;
+
+ static char retstr[EXR_PASS_MAXNAME];
+ const char delims[] = {'.', '\0'};
+ const char *sep;
+ const char *token;
+ size_t len;
+
+ len = BLI_str_rpartition(passname, delims, &sep, &token);
+
+ if (sep) {
+ BLI_snprintf(retstr, sizeof(retstr), "%.*s.%s.%s", (int)len, passname, viewname, token);
+ }
+ else {
+ BLI_snprintf(retstr, sizeof(retstr), "%s.%s", passname, viewname);
+ }
+
+ return retstr;
+}
+
/* adds flattened ExrChannels */
/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
+/* passname does not include view */
+void IMB_exr_add_channel(void *handle,
+ const char *layname, const char *passname, const char *viewname,
+ int xstride, int ystride, float *rect,
+ bool use_half_float)
{
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+ echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan->m = new MultiViewChannelName ();
- if (layname) {
- 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);
+ if (layname && layname[0] != '\0') {
+ echan->m->name = layname;
+ echan->m->name.append(".");
+ echan->m->name.append(passname);
+ }
+ else {
+ echan->m->name.assign(passname);
+ }
+
+ echan->m->internal_name = echan->m->name;
+
+ echan->m->view.assign(viewname ? viewname : "");
+
+ /* quick look up */
+ echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
- BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(echan->m->name.c_str(), echan->m->view.c_str());
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
+ }
+ else if (data->multiView->size() > 1) {
+ std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
}
else {
- BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
+ BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
}
echan->xstride = xstride;
echan->ystride = ystride;
echan->rect = rect;
+ echan->use_half_float = use_half_float;
+
+ if (echan->use_half_float) {
+ data->num_half_channels++;
+ }
- // printf("added channel %s\n", echan->name);
+ exr_printf("added channel %s\n", echan->name);
BLI_addtail(&data->channels, echan);
}
-/* only used for writing temp. render results (not image files) */
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
+/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const StampData *stamp)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
@@ -617,14 +852,24 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->width = width;
data->height = height;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
+ bool is_singlelayer, is_multilayer, is_multiview;
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ header.channels().insert(echan->name,
+ Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
+ }
openexr_header_compression(&header, compress);
- // openexr_header_metadata(&header, ibuf); // no imbuf. cant write
+ BKE_stamp_info_callback(&header, stamp, openexr_header_metadata_callback);
/* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
- header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+ imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
+
+ if (is_multilayer)
+ header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+
+ if (is_multiview)
+ addMultiView(header, *data->multiView);
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
@@ -632,7 +877,7 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->ofile_stream = new OFileStream(filename);
data->ofile = new OutputFile(*(data->ofile_stream), header);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
delete data->ofile;
@@ -645,10 +890,13 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
return (data->ofile != NULL);
}
+/* only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
+ std::vector<Header> headers;
ExrChannel *echan;
data->tilex = tilex;
@@ -657,26 +905,49 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
data->height = height;
data->mipmap = mipmap;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
-
header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
- header.lineOrder() = RANDOM_Y;
header.compression() = RLE_COMPRESSION;
+ header.setType(TILEDIMAGE);
header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
+ int numparts = data->multiView->size();
+
+ /* copy header from all parts of input to our header array
+ * those temporary files have one part per view */
+ for (int i = 0; i < numparts; i++) {
+ headers.push_back (header);
+ headers[headers.size() - 1].setView((*(data->multiView))[i]);
+ headers[headers.size() - 1].setName((*(data->multiView))[i]);
+ }
+
+ exr_printf("\nIMB_exrtile_begin_write\n");
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------\n");
+
+ /* assign channels */
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ /* Tiles are expected to be saved with full float currently. */
+ BLI_assert(echan->use_half_float == 0);
+
+ echan->m->internal_name = echan->m->name;
+ echan->m->part_number = echan->view_id;
+
+ headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
+ }
+
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filename);
- data->tofile = new TiledOutputFile(*(data->ofile_stream), header);
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
}
catch (const std::exception &) {
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
}
}
@@ -685,12 +956,13 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
if (BLI_exists(filename) && BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */
/* avoid crash/abort when we don't have permission to write here */
try {
data->ifile_stream = new IFileStream(filename);
- data->ifile = new InputFile(*(data->ifile_stream));
+ data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
delete data->ifile;
@@ -701,14 +973,24 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
if (data->ifile) {
- Box2i dw = data->ifile->header().dataWindow();
+ Box2i dw = data->ifile->header(0).dataWindow();
data->width = *width = dw.max.x - dw.min.x + 1;
data->height = *height = dw.max.y - dw.min.y + 1;
- const ChannelList &channels = data->ifile->header().channels();
+ imb_exr_get_views(*data->ifile, *data->multiView);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
return 1;
}
@@ -717,6 +999,7 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
/* still clumsy name handling, layers/channels can be ordered as list in list later */
+/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
@@ -741,37 +1024,53 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->rect = rect;
}
else
- printf("IMB_exrtile_set_channel error %s\n", name);
+ printf("IMB_exr_set_channel error %s\n", name);
}
-void IMB_exrtile_clear_channels(void *handle)
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
- BLI_freelistN(&data->channels);
-}
-
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
-{
- ExrHandle *data = (ExrHandle *)handle;
- FrameBuffer frameBuffer;
ExrChannel *echan;
+ char name[EXR_TOT_MAXNAME + 1];
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ if (layname) {
+ 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);
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
+ BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
+ else
+ BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
- data->tofile->setFrameBuffer(frameBuffer);
-
- try {
- // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
- data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(name, viewname);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
- catch (const std::exception &exc) {
- std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ else if (data->multiView->size() > 1) {
+ size_t view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
+ std::string raw_name = insertViewName(name, *data->multiView, view_id);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
+
+ echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
+
+ if (echan)
+ return echan->rect;
+
+ return NULL;
+}
+
+void IMB_exr_clear_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *chan;
+
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
+ delete chan->m;
+
+ BLI_freelistN(&data->channels);
}
void IMB_exr_write_channels(void *handle)
@@ -781,70 +1080,223 @@ void IMB_exr_write_channels(void *handle)
ExrChannel *echan;
if (data->channels.first) {
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- /* last scanline, stride negative */
- float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ const size_t num_pixels = ((size_t)data->width) * data->height;
+ half *rect_half = NULL, *current_rect_half;
+
+ /* We allocate teporary storage for half pixels for all the channels at once. */
+ if (data->num_half_channels != 0) {
+ rect_half = (half *)MEM_mallocN(sizeof(half) * data->num_half_channels * num_pixels, __func__);
+ current_rect_half = rect_half;
+ }
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ /* Writting starts from last scanline, stride negative. */
+ if (echan->use_half_float) {
+ float *rect = echan->rect;
+ half *cur = current_rect_half;
+ for (size_t i = 0; i < num_pixels; ++i, ++cur) {
+ *cur = rect[i * echan->xstride];
+ }
+ half *rect_to_write = current_rect_half + (data->height - 1) * data->width;
+ frameBuffer.insert(echan->name, Slice(Imf::HALF, (char *)rect_to_write,
+ sizeof(half), -data->width * sizeof(half)));
+ current_rect_half += num_pixels;
+ }
+ else {
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
+ echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
+ }
}
data->ofile->setFrameBuffer(frameBuffer);
try {
data->ofile->writePixels(data->height);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
}
+ /* Free temporary buffers. */
+ if (rect_half != NULL) {
+ MEM_freeN(rect_half);
+ }
}
else {
printf("Error: attempt to save MultiLayer without layers.\n");
}
}
-void IMB_exr_read_channels(void *handle)
+/* temporary function, used for FSA and Save Buffers */
+/* called once per tile * view */
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
FrameBuffer frameBuffer;
ExrChannel *echan;
+ std::string view(viewname);
+ const size_t view_id = imb_exr_get_multiView_id(*data->multiView, view);
+
+ exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------------\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ /* eventually we can make the parts' channels to include
+ only the current view TODO */
+ if (strcmp(viewname, echan->m->view.c_str()) != 0)
+ continue;
+
+ exr_printf("%d %-6s %-22s \"%s\"\n",
+ echan->m->part_number,
+ echan->m->view.c_str(),
+ echan->m->name.c_str(),
+ echan->m->internal_name.c_str()
+ );
+
+ float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ frameBuffer.insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ echan->ystride * sizeof(float)
+ )
+ );
+ }
+
+ TiledOutputPart out (*data->mpofile, view_id);
+ out.setFrameBuffer(frameBuffer);
+
+ try {
+ // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
+ out.writeTile(partx / data->tilex, party / data->tiley, level);
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+/* called only when handle has all views */
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ const size_t view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
+ int numparts = (view_id == -1 ? data->parts : view_id + 1);
+ std::vector <FrameBuffer> frameBuffers(numparts);
+ std::vector <OutputPart> outputParts;
+ ExrChannel *echan;
+ int i, part;
+
+ if (data->channels.first == NULL)
+ return;
+
+ exr_printf("\nIMB_exrmultiview_write_channels()\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ if (view_id != -1 && echan->view_id != view_id)
+ continue;
+
+ part = (view_id == -1 ? echan->m->part_number : echan->view_id);
+
+ /* last scanline, stride negative */
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffers[part].insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ -echan->ystride * sizeof(float))
+ );
+ }
+
+ for (i = 0; i < numparts; i++) {
+ OutputPart out(*data->mpofile, i);
+ out.setFrameBuffer(frameBuffers[i]);
+ outputParts.push_back(out);
+ }
+
+ try {
+ for (i = 0; i < numparts; i++) {
+ if (view_id != -1 && i != view_id)
+ continue;
+
+ outputParts[i].writePixels(data->height);
+ }
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
+ int numparts = data->ifile->parts();
+ std::vector<FrameBuffer> frameBuffers(numparts);
+ std::vector<InputPart> inputParts;
/* check if exr was saved with previous versions of blender which flipped images */
- const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
+ const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
+ exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
if (echan->rect) {
if (flip)
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)echan->rect,
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)echan->rect,
echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
else
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
}
else
- printf("warning, channel with no rect set %s\n", echan->name);
+ printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
- data->ifile->setFrameBuffer(frameBuffer);
+ for (int i = 0; i < numparts; i++) {
+ InputPart in (*data->ifile, i);
+ in.setFrameBuffer(frameBuffers[i]);
+ inputParts.push_back(in);
+ }
try {
- data->ifile->readPixels(0, data->height - 1);
+ for (int i = 0; i < numparts; i++) {
+ Header header = inputParts[i].header();
+ exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(0, data->height - 1);
+ }
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
}
}
void IMB_exr_multilayer_convert(void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
void * (*addlayer)(void *base, const char *str),
void (*addpass)(void *base, void *lay, const char *str,
- float *rect, int totchan, const char *chan_id))
+ float *rect, int totchan, const char *chan_id,
+ const char *view))
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ /* RenderResult needs at least one RenderView */
+ if (data->multiView->size() == 0) {
+ addview(base, "");
+ }
+ else {
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+ }
+
if (BLI_listbase_is_empty(&data->layers)) {
printf("cannot convert multilayer, no layers in handle\n");
return;
@@ -854,32 +1306,99 @@ void IMB_exr_multilayer_convert(void *handle, void *base,
void *laybase = addlayer(base, lay->name);
if (laybase) {
for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
- addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
+ addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
pass->rect = NULL;
}
}
}
}
+void IMB_exr_multiview_convert(void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
+ const int frame)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ ExrLayer *lay;
+ ExrPass *pass;
+ ImBuf *ibuf = NULL;
+ const bool is_alpha = exr_has_alpha(*file);
+ Box2i dw = file->header(0).dataWindow();
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
+ const bool is_depth = exr_has_zbuffer(*file);
+
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+
+ if (BLI_listbase_is_empty(&data->layers)) {
+ printf("cannot convert multiviews, no views in handle\n");
+ return;
+ }
+
+ /* there is one float/pass per layer (layer here is a view) */
+ BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
+ lay = (ExrLayer *)data->layers.first;
+ for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
+ if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
+ ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
+
+ if (!ibuf) {
+ printf("error creating multiview buffer\n");
+ return;
+ }
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, pass->rect, pass->totchan,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
+ }
+
+ if (is_depth) {
+ ExrPass *zpass;
+ for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
+ if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
+ addzbuffloatImBuf(ibuf);
+ memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
+ }
+ }
+ }
+
+ addbuffer(base, pass->view, ibuf, frame);
+ }
+ }
+}
void IMB_exr_close(void *handle)
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ ExrChannel *chan;
delete data->ifile;
delete data->ifile_stream;
delete data->ofile;
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
+ delete data->multiView;
data->ifile = NULL;
data->ifile_stream = NULL;
data->ofile = NULL;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
+ delete chan->m;
+ }
BLI_freelistN(&data->channels);
for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
@@ -899,19 +1418,21 @@ void IMB_exr_close(void *handle)
/* get a substring from the end of the name, separated by '.' */
static int imb_exr_split_token(const char *str, const char *end, const char **token)
{
- ptrdiff_t maxlen = end - str;
- int len = 0;
- while (len < maxlen && *(end - len - 1) != '.') {
- len++;
+ const char delims[] = {'.', '\0'};
+ const char *sep;
+
+ BLI_str_partition_ex(str, end, delims, &sep, token, true);
+
+ if (!sep) {
+ *token = str;
}
- *token = end - len;
- return len;
+ return (int)(end - *token);
}
static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
{
- const char *name = echan->name;
+ const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
char tokenbuf[EXR_TOT_MAXNAME];
@@ -1020,7 +1541,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
}
/* creates channels, makes a hierarchy and assigns memory to channels */
-static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
+static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
{
ExrLayer *lay;
ExrPass *pass;
@@ -1029,30 +1550,59 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
int a;
char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
- data->ifile = file;
+ data->ifile_stream = &file_stream;
+ data->ifile = &file;
+
data->width = width;
data->height = height;
- const ChannelList &channels = data->ifile->header().channels();
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ data->multiView = new StringVector();
+ imb_exr_get_views(*data->ifile, *data->multiView);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
/* now try to sort out how to assign memory to the channels */
/* first build hierarchical layer list */
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- if (imb_exr_split_channel_name(echan, layname, passname) ) {
+ if (imb_exr_split_channel_name(echan, layname, passname)) {
+
+ const char *view = echan->m->view.c_str();
+ char internal_name[EXR_PASS_MAXNAME];
+
+ BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
+
+ if (view[0] != '\0') {
+ char tmp_pass[EXR_PASS_MAXNAME];
+ BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
+ BLI_strncpy(passname, tmp_pass, sizeof(passname));
+ }
+
ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
pass->chan[pass->totchan] = echan;
pass->totchan++;
+ pass->view_id = echan->view_id;
+ BLI_strncpy(pass->view, view, sizeof(pass->view));
+ BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
+
if (pass->totchan >= EXR_PASS_MAXCHAN)
break;
}
}
if (echan) {
- printf("error, too many channels in one pass: %s\n", echan->name);
+ printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
IMB_exr_close(data);
return NULL;
}
@@ -1122,20 +1672,52 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
/* ********************************************************* */
/* debug only */
-static void exr_print_filecontents(InputFile *file)
+static void exr_printf(const char *fmt, ...)
{
- const ChannelList &channels = file->header().channels();
+#if 0
+ char output[1024];
+ va_list args;
+ va_start(args, fmt);
+ std::vsprintf(output, fmt, args);
+ va_end(args);
+ printf("%s", output);
+#else
+ (void)fmt;
+#endif
+}
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
- const Channel &channel = i.channel();
- printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+static void exr_print_filecontents(MultiPartInputFile& file)
+{
+ int numparts = file.parts();
+ if (numparts == 1 && hasMultiView(file.header(0))) {
+ const StringVector views = multiView(file.header(0));
+ printf("OpenEXR-load: MultiView file\n");
+ printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
+ for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
+ printf("OpenEXR-load: Found view %s\n", (*i).c_str());
+ }
+ }
+ else if (numparts > 1) {
+ printf("OpenEXR-load: MultiPart file\n");
+ for (int i = 0; i < numparts; i++) {
+ if (file.header(i).hasView())
+ printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
+ }
+ }
+
+ for (int j = 0; j < numparts; j++) {
+ const ChannelList& channels = file.header(j).channels();
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
+ const Channel& channel = i.channel();
+ printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+ }
}
}
/* for non-multilayer, map R G B A channel names to something that's in this file */
-static const char *exr_rgba_channelname(InputFile *file, const char *chan)
+static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
{
- const ChannelList &channels = file->header().channels();
+ const ChannelList& channels = file.header(0).channels();
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
/* const Channel &channel = i.channel(); */ /* Not used yet */
@@ -1150,48 +1732,48 @@ static const char *exr_rgba_channelname(InputFile *file, const char *chan)
return chan;
}
-static bool exr_has_rgb(InputFile *file)
+static bool exr_has_rgb(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("R") != NULL &&
- file->header().channels().findChannel("G") != NULL &&
- file->header().channels().findChannel("B") != NULL;
+ return file.header(0).channels().findChannel("R") != NULL &&
+ file.header(0).channels().findChannel("G") != NULL &&
+ file.header(0).channels().findChannel("B") != NULL;
}
-static bool exr_has_luma(InputFile *file)
+static bool exr_has_luma(MultiPartInputFile& file)
{
/* Y channel is the luma and should always present fir luma space images,
* optionally it could be also channels for chromas called BY and RY.
*/
- return file->header().channels().findChannel("Y") != NULL;
+ return file.header(0).channels().findChannel("Y") != NULL;
}
-static bool exr_has_chroma(InputFile *file)
+static bool exr_has_chroma(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("BY") != NULL &&
- file->header().channels().findChannel("RY") != NULL;
+ return file.header(0).channels().findChannel("BY") != NULL &&
+ file.header(0).channels().findChannel("RY") != NULL;
}
-static int exr_has_zbuffer(InputFile *file)
+static bool exr_has_zbuffer(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("Z") == NULL);
+ return !(file.header(0).channels().findChannel("Z") == NULL);
}
-static int exr_has_alpha(InputFile *file)
+static bool exr_has_alpha(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("A") == NULL);
+ return !(file.header(0).channels().findChannel("A") == NULL);
}
-static bool exr_is_multilayer(InputFile *file)
+static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
- const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
- const ChannelList &channels = file->header().channels();
+ const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+ const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
if (comments || layerNames.size() > 1)
- return 1;
+ return true;
if (layerNames.size()) {
/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1206,17 +1788,123 @@ static bool exr_is_multilayer(InputFile *file)
size_t pos = layerName.rfind ('.');
if (pos == std::string::npos)
- return 1;
+ return true;
}
}
- return 0;
+ return false;
+}
+
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
+{
+ std::set <std::string> layerNames;
+
+ *r_singlelayer = true;
+ *r_multilayer = *r_multiview = false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ if (views.size() && views[0] != "")
+ *r_multiview = true;
+
+ if (layerNames.size()) {
+ /* if layerNames is not empty, it means at least one layer is non-empty,
+ * but it also could be layers without names in the file and such case
+ * shall be considered a multilayer exr
+ *
+ * that's what we do here: test whether there're empty layer names together
+ * with non-empty ones in the file
+ */
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ /* see if any layername differs from a viewname */
+ if (imb_exr_get_multiView_id(views, *i) == -1) {
+ std::string layerName = *i;
+ size_t pos = layerName.rfind ('.');
+
+ if (pos != std::string::npos) {
+ *r_multilayer = true;
+ *r_singlelayer = false;
+ return;
+ }
+ }
+ }
+ else {
+ *r_singlelayer = true;
+ *r_multilayer = false;
+ *r_multiview = false;
+ }
+
+ BLI_assert(r_singlelayer != r_multilayer);
+}
+
+bool IMB_exr_has_singlelayer_multiview(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ std::set <std::string> layerNames;
+ const ChannelList& channels = file->header(0).channels();
+ const StringAttribute *comments;
+
+ if (exr_has_multiview(*file) == false)
+ return false;
+
+ comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+
+ if (comments)
+ return false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ /* returns false if any layer differs from views list */
+ if (layerNames.size())
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
+ return false;
+
+ return true;
+}
+
+bool IMB_exr_has_multilayer(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ return imb_exr_is_multilayer_file(*data->ifile);
+}
+
+static bool exr_has_multiview(MultiPartInputFile& file)
+{
+ return hasMultiView(file.header(0));
+}
+
+static bool exr_has_multipart_file(MultiPartInputFile& file)
+{
+ return file.parts() > 1;
+}
+
+/* it returns true if the file is multilayer or multiview */
+static bool imb_exr_is_multi(MultiPartInputFile& file)
+{
+ /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
+ if (exr_has_multipart_file(file))
+ return true;
+
+ if (exr_has_multiview(file))
+ return true;
+
+ if (imb_exr_is_multilayer_file(file))
+ return true;
+
+ return false;
}
struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
- InputFile *file = NULL;
+ Mem_IStream *membuf = NULL;
+ MultiPartInputFile *file = NULL;
if (imb_is_a_openexr(mem) == 0) return(NULL);
@@ -1224,11 +1912,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
try
{
- Mem_IStream *membuf = new Mem_IStream(mem, size);
bool is_multi;
- file = new InputFile(*membuf);
- Box2i dw = file->header().dataWindow();
+ membuf = new Mem_IStream(mem, size);
+ file = new MultiPartInputFile(*membuf);
+
+ Box2i dw = file->header(0).dataWindow();
const int width = dw.max.x - dw.min.x + 1;
const int height = dw.max.y - dw.min.y + 1;
@@ -1236,38 +1925,54 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
if (0) // debug
- exr_print_filecontents(file);
+ exr_print_filecontents(*file);
- is_multi = exr_is_multilayer(file);
+ is_multi = imb_exr_is_multi(*file);
/* do not make an ibuf when */
if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
printf("Error: can't process EXR multilayer file\n");
}
else {
- const int is_alpha = exr_has_alpha(file);
+ const int is_alpha = exr_has_alpha(*file);
ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
- if (hasXDensity(file->header())) {
- ibuf->ppm[0] = xDensity(file->header()) * 39.3700787f;
- ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header().pixelAspectRatio();
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
}
ibuf->ftype = OPENEXR;
if (!(flags & IB_test)) {
- if (is_multi) { /* only enters with IB_multilayer flag set */
+
+ if (flags & IB_metadata) {
+ const Header & header = file->header(0);
+ Header::ConstIterator iter;
+
+ for (iter = header.begin(); iter != header.end(); iter++) {
+ const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
+
+ /* not all attributes are string attributes so we might get some NULLs here */
+ if (attrib) {
+ IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
+ ibuf->flags |= IB_metadata;
+ }
+ }
+ }
+
+ if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
/* constructs channels for reading, allocates memory in channels */
- ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
+ ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
if (handle) {
IMB_exr_read_channels(handle);
ibuf->userdata = handle; /* potential danger, the caller has to check for this! */
}
}
else {
- const bool has_rgb = exr_has_rgb(file);
- const bool has_luma = exr_has_luma(file);
+ const bool has_rgb = exr_has_rgb(*file);
+ const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
int xstride = sizeof(float) * 4;
@@ -1281,27 +1986,27 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
first += 4 * (height - 1) * width;
if (has_rgb) {
- frameBuffer.insert(exr_rgba_channelname(file, "R"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "R"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "G"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "G"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "B"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "B"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride));
}
else if (has_luma) {
- frameBuffer.insert(exr_rgba_channelname(file, "Y"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "BY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
- frameBuffer.insert(exr_rgba_channelname(file, "RY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
}
/* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
- frameBuffer.insert(exr_rgba_channelname(file, "A"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "A"),
Slice(Imf::FLOAT, (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
- if (exr_has_zbuffer(file)) {
+ if (exr_has_zbuffer(*file)) {
float *firstz;
addzbuffloatImBuf(ibuf);
@@ -1310,8 +2015,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)firstz, sizeof(float), -width * sizeof(float)));
}
- file->setFrameBuffer(frameBuffer);
- file->readPixels(dw.min.y, dw.max.y);
+ InputPart in (*file, 0);
+ in.setFrameBuffer(frameBuffer);
+ in.readPixels(dw.min.y, dw.max.y);
// XXX, ImBuf has no nice way to deal with this.
// ideally IM_rect would be used when the caller wants a rect BUT
@@ -1325,7 +2031,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
if (!has_rgb && has_luma) {
size_t a;
- if (exr_has_chroma(file)) {
+ if (exr_has_chroma(*file)) {
for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
@@ -1342,6 +2048,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
/* file is no longer needed */
+ delete membuf;
delete file;
}
}
@@ -1351,11 +2058,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
return(ibuf);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
std::cerr << exc.what() << std::endl;
if (ibuf) IMB_freeImBuf(ibuf);
delete file;
+ delete membuf;
return (0);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 376d2401b1c..70ba4978124 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -39,34 +39,63 @@
/* This api also supports max 8 channels per pass now. easy to fix! */
#define EXR_LAY_MAXNAME 64
#define EXR_PASS_MAXNAME 64
+#define EXR_VIEW_MAXNAME 64
#define EXR_TOT_MAXNAME 64
-#define EXR_PASS_MAXCHAN 8
+#define EXR_PASS_MAXCHAN 24
#ifdef __cplusplus
extern "C" {
#endif
+struct StampData;
+
void *IMB_exr_get_handle(void);
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+void *IMB_exr_get_handle_name(const char *name);
+void IMB_exr_add_channel(void *handle,
+ const char *layname, const char *passname, const char *view,
+ int xstride, int ystride,
+ float *rect,
+ bool use_half_float);
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height);
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress);
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const struct StampData *stamp);
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *view);
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level);
-void IMB_exrtile_clear_channels(void *handle);
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname);
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname);
+void IMB_exr_clear_channels(void *handle);
+
+void IMB_exr_multilayer_convert(
+ void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
+ void * (*addlayer)(void *base, const char *str),
+ void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view));
+
+void IMB_exr_multiview_convert(
+ void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int frame);
-void IMB_exr_multilayer_convert(void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id));
+bool IMB_exr_multiview_save(
+ struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ struct ImBuf * (*getbuffer)(void *base, const size_t view_id));
void IMB_exr_close(void *handle);
+void IMB_exr_add_view(void *handle, const char *name);
+
+bool IMB_exr_has_multilayer(void *handle);
+bool IMB_exr_has_singlelayer_multiview(void *handle);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 21fa878c08a..c198cac6357 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -32,26 +32,52 @@
#include "openexr_api.h"
#include "openexr_multi.h"
-
void *IMB_exr_get_handle (void) {return NULL;}
-void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void *IMB_exr_get_handle_name (const char * /*name*/) { return NULL;}
+void IMB_exr_add_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/,
+ int /*xstride*/, int /*ystride*/, float * /*rect*/,
+ bool /*use_half_float*/) { }
+
+int IMB_exr_begin_read (void * /*handle*/, const char * /*filename*/, int * /*width*/, int * /*height*/) { return 0;}
+int IMB_exr_begin_write (void * /*handle*/, const char * /*filename*/, int /*width*/, int /*height*/, int /*compress*/, const struct StampData * /*stamp*/) { return 0;}
+void IMB_exrtile_begin_write (void * /*handle*/, const char * /*filename*/, int /*mipmap*/, int /*width*/, int /*height*/, int /*tilex*/, int /*tiley*/) { }
-int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;}
-int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;}
-void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; }
+void IMB_exr_set_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, int /*xstride*/, int /*ystride*/, float * /*rect*/) { }
+float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/) { return NULL; }
-void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void IMB_exr_read_channels (void * /*handle*/) { }
+void IMB_exr_write_channels (void * /*handle*/) { }
+void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { }
+void IMB_exrmultiview_write_channels(void * /*handle*/, const char * /*viewname*/) { }
+void IMB_exr_clear_channels (void * /*handle*/) { }
+
+void IMB_exr_multilayer_convert(
+ void * /*handle*/, void * /*base*/,
+ void * (* /*addview*/)(void *base, const char *str),
+ void * (* /*addlayer*/)(void *base, const char *str),
+ void (* /*addpass*/)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view))
+{
+}
-void IMB_exr_read_channels (void *handle) { (void)handle; }
-void IMB_exr_write_channels (void *handle) { (void)handle; }
-void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; }
-void IMB_exrtile_clear_channels (void *handle) { (void)handle; }
+void IMB_exr_multiview_convert(
+ void * /*handle*/, void * /*base*/,
+ void (* /*addview*/)(void *base, const char *str),
+ void (* /*addbuffer*/)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int /*frame*/)
+{
+}
-void IMB_exr_multilayer_convert (void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id))
+bool IMB_exr_multiview_save(
+ struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const size_t /*totviews*/,
+ const char * (* /*getview*/)(void *base, size_t view_id),
+ struct ImBuf * (* /*getbuffer*/)(void *base, const size_t view_id))
{
- (void)handle; (void)base; (void)addlayer; (void)addpass;
+ return false;
}
-void IMB_exr_close (void *handle) { (void)handle; }
+void IMB_exr_close (void * /*handle*/) { }
+
+void IMB_exr_add_view(void * /*handle*/, const char * /*name*/) { }
+bool IMB_exr_has_multilayer(void * /*handle*/) { return false; }
+bool IMB_exr_has_singlelayer_multiview(void * /*handle*/) { return false; }
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 683bdabcd6c..1b6b413838d 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -138,6 +138,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
int channels_in_float = ibuf->channels ? ibuf->channels : 4;
float (*chanel_colormanage_cb)(float);
+ size_t num_bytes;
/* use the jpeg quality setting for compression */
int compression;
@@ -184,11 +185,11 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
}
/* copy image data */
-
+ num_bytes = ((size_t)ibuf->x) * ibuf->y * bytesperpixel;
if (is_16bit)
- pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
+ pixels16 = MEM_mallocN(num_bytes * sizeof(unsigned short), "png 16bit pixels");
else
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");
+ pixels = MEM_mallocN(num_bytes * sizeof(unsigned char), "png 8bit pixels");
if (pixels == NULL && pixels16 == NULL) {
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -312,7 +313,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_straight[0]);
rgb[1] = chanel_colormanage_cb(from_straight[1]);
rgb[2] = chanel_colormanage_cb(from_straight[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 4;
}
}
@@ -321,7 +322,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_float[0]);
rgb[1] = chanel_colormanage_cb(from_float[1]);
rgb[2] = chanel_colormanage_cb(from_float[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 3;
}
}
@@ -454,13 +455,13 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
if (is_16bit) {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
+ ((unsigned short *)pixels16 + (((size_t)i) * ibuf->x) * bytesperpixel);
}
}
else {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
}
@@ -682,7 +683,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
else {
imb_addrectImBuf(ibuf);
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
+ pixels = MEM_mallocN(((size_t)ibuf->x) * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
if (pixels == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
@@ -698,7 +699,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
/* set the individual row-pointers to point at the correct offsets */
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
png_read_image(png_ptr, row_pointers);
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index bb09c57d1e5..38d54e64035 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -103,7 +103,7 @@ static void imb_handle_alpha(ImBuf *ibuf, int flags, char colorspace[IM_MAX_SPAC
ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (mem == NULL) {
@@ -133,7 +133,7 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
static ImBuf *IMB_ibImageFromFile(const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (colorspace)
@@ -209,6 +209,8 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
int file, a;
char filepath_tx[IB_FILENAME_SIZE];
+ BLI_assert(!BLI_path_is_rel(filepath));
+
imb_cache_filename(filepath_tx, filepath, flags);
file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
@@ -237,6 +239,8 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
char filepath_tx[IB_FILENAME_SIZE];
char colorspace[IM_MAX_SPACE] = "\0";
+ BLI_assert(!BLI_path_is_rel(filepath));
+
imb_cache_filename(filepath_tx, filepath, flags);
file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
@@ -257,7 +261,7 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int *rect)
{
- ImFileType *type;
+ const ImFileType *type;
unsigned char *mem;
size_t size;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4001b681ad9..c7b347cb20c 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -322,30 +322,30 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
if (do_char) {
- drect = dbuf->rect + desty * dbuf->x + destx;
- orect = obuf->rect + origy * obuf->x + origx;
+ drect = dbuf->rect + ((size_t)desty) * dbuf->x + destx;
+ orect = obuf->rect + ((size_t)origy) * obuf->x + origx;
}
if (do_float) {
- drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
- orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
+ drectf = dbuf->rect_float + (((size_t)desty) * dbuf->x + destx) * 4;
+ orectf = obuf->rect_float + (((size_t)origy) * obuf->x + origx) * 4;
}
if (dmaskrect)
- dmaskrect += origy * obuf->x + origx;
+ dmaskrect += ((size_t)origy) * obuf->x + origx;
destskip = dbuf->x;
origskip = obuf->x;
if (sbuf) {
- if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
- if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4;
+ if (do_char) srect = sbuf->rect + ((size_t)srcy) * sbuf->x + srcx;
+ if (do_float) srectf = sbuf->rect_float + (((size_t)srcy) * sbuf->x + srcx) * 4;
srcskip = sbuf->x;
if (cmaskrect)
- cmaskrect += srcy * sbuf->x + srcx;
+ cmaskrect += ((size_t)srcy) * sbuf->x + srcx;
if (texmaskrect)
- texmaskrect += srcy * sbuf->x + srcx;
+ texmaskrect += ((size_t)srcy) * sbuf->x + srcx;
}
else {
srect = drect;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
new file mode 100644
index 00000000000..3b9da639a86
--- /dev/null
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -0,0 +1,1292 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/stereoimbuf.c
+ * \ingroup imbuf
+ */
+
+#include <stddef.h>
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filetype.h"
+#include "IMB_metadata.h"
+#include "IMB_colormanagement_intern.h"
+
+#include "imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+
+/* prototypes */
+struct Stereo3DData;
+static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+
+typedef struct Stereo3DData {
+ struct { float *left, *right, *stereo; } rectf;
+ struct { uchar *left, *right, *stereo; } rect;
+ size_t x, y, channels;
+ bool is_float;
+} Stereo3DData;
+
+static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][3], from[0][3]);
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][3], from[0][3]);
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(float) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ const float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(uchar) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width * 2;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/**************************** dimension utils ****************************************/
+
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width : width * 2;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height : height * 2;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width / 2 : width;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height / 2 : height;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+/**************************** un/squeeze frame ****************************************/
+
+static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_squeeze_rectf(float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rectfloat);
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, rectf, channels,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rectf, ibuf->rect_float, x * y * sizeof(float[4]));
+ IMB_freeImBuf(ibuf);
+}
+
+static void imb_stereo3d_squeeze_rect(int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rect);
+
+ IMB_buffer_byte_from_byte(
+ (unsigned char *)ibuf->rect, (unsigned char *)rect,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rect, ibuf->rect, x * y * sizeof(unsigned int));
+ IMB_freeImBuf(ibuf);
+}
+
+
+/*************************** preparing to call the write functions **************************/
+
+static void imb_stereo3d_data_initialize(
+ Stereo3DData *s3d_data, const bool is_float,
+ const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right, int *rect_stereo,
+ float *rectf_left, float *rectf_right, float *rectf_stereo)
+{
+ s3d_data->is_float = is_float;
+ s3d_data->x = x;
+ s3d_data->y = y;
+ s3d_data->channels = channels;
+ s3d_data->rect.left = (uchar *)rect_left;
+ s3d_data->rect.right = (uchar *)rect_right;
+ s3d_data->rect.stereo = (uchar *)rect_stereo;
+ s3d_data->rectf.left = rectf_left;
+ s3d_data->rectf.right = rectf_right;
+ s3d_data->rectf.stereo = rectf_stereo;
+}
+
+int *IMB_stereo3d_from_rect(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right)
+{
+ int *r_rect;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rect;
+}
+
+float *IMB_stereo3d_from_rectf(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right)
+{
+ float *r_rectf;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rectf;
+}
+
+/* left/right are always float */
+ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
+{
+ ImBuf *ibuf_stereo = NULL;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, ibuf_left->x, ibuf_left->y, &width, &height);
+ ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_stereo->flags = ibuf_left->flags;
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo->rect_float);
+
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_ImBuf(ibuf_stereo, &im_format->stereo3d_format, ibuf_left->x, ibuf_left->y);
+
+ return ibuf_stereo;
+}
+
+static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_write_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_write_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_write_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_write_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************** reading stereo imbufs **********************/
+
+static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_from = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_from = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(float) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.right;
+ uchar *rect_right = s3d->rect.left;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(uchar) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width * 2;
+ const int stride_to = width;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(float) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ /* always RGBA input/output */
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(float) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+
+/*************************** preparing to call the read functions **************************/
+
+/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
+void IMB_ImBufFromStereo3d(
+ Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d,
+ ImBuf **r_ibuf_left, ImBuf **r_ibuf_right)
+{
+ Stereo3DData s3d_data = {{NULL}};
+ ImBuf *ibuf_left, *ibuf_right;
+ size_t width, height;
+ const bool is_float = (ibuf_stereo3d->rect_float != NULL);
+
+ IMB_stereo3d_read_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+
+ ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+ ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_left->flags = ibuf_stereo3d->flags;
+ ibuf_right->flags = ibuf_stereo3d->flags;
+
+ /* we always work with unsqueezed formats */
+ IMB_stereo3d_write_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+ imb_stereo3d_unsqueeze_ImBuf(ibuf_stereo3d, s3d, width, height);
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo3d->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo3d->rect_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+
+ if (ibuf_stereo3d->flags & (IB_zbuf | IB_zbuffloat)) {
+ if (is_float) {
+ addzbuffloatImBuf(ibuf_left);
+ addzbuffloatImBuf(ibuf_right);
+ }
+ else {
+ addzbufImBuf(ibuf_left);
+ addzbufImBuf(ibuf_right);
+ }
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 1,
+ (int *)ibuf_left->zbuf, (int *)ibuf_right->zbuf, (int *)ibuf_stereo3d->zbuf,
+ ibuf_left->zbuf_float, ibuf_right->zbuf_float, ibuf_stereo3d->zbuf_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+ }
+
+ IMB_freeImBuf(ibuf_stereo3d);
+
+ *r_ibuf_left = ibuf_left;
+ *r_ibuf_right = ibuf_right;
+}
+
+static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_read_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_read_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_read_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_read_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index 70b71ec4182..40dcdc9d24a 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -568,7 +568,7 @@ ImBuf *imb_loadtarga(unsigned char *mem, size_t mem_size, int flags, char colors
else ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, (tga.pixsize + 0x7) & ~0x7, IB_rect);
if (ibuf == NULL) return NULL;
- ibuf->ftype = TGA;
+ ibuf->ftype = (tga.imgtyp < 4) ? RAWTGA : TGA;
mem = mem + 18 + tga.numid;
cp[0] = 0xff;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 118f0405303..7a949b7ffea 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -200,6 +200,17 @@ static void escape_uri_string(const char *string, char *escaped_string, int esca
/** ----- end of adapted code from glib --- */
+static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, char *r_hash)
+{
+ switch (source) {
+ case THB_SOURCE_FONT:
+ return IMB_thumb_load_font_get_hash(r_hash);
+ default:
+ r_hash[0] = '\0';
+ return false;
+ }
+}
+
static int uri_from_filename(const char *path, char *uri)
{
char orig_uri[URI_MAX];
@@ -239,47 +250,68 @@ static int uri_from_filename(const char *path, char *uri)
return 1;
}
-static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+static bool thumbpathname_from_uri(
+ const char *uri, char *r_path, const int path_len, char *r_name, int name_len, ThumbSize size)
{
- char hexdigest[33];
- unsigned char digest[16];
+ char name_buff[40];
+
+ if (r_path && !r_name) {
+ r_name = name_buff;
+ name_len = sizeof(name_buff);
+ }
- BLI_hash_md5_buffer(uri, strlen(uri), digest);
- hexdigest[0] = '\0';
- BLI_snprintf(thumb, thumb_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+ if (r_name) {
+ char hexdigest[33];
+ unsigned char digest[16];
+ BLI_hash_md5_buffer(uri, strlen(uri), digest);
+ hexdigest[0] = '\0';
+ BLI_snprintf(r_name, name_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_name);
+ }
- // printf("%s: '%s' --> '%s'\n", __func__, uri, thumb);
+ if (r_path) {
+ char tmppath[FILE_MAX];
+
+ if (get_thumb_dir(tmppath, size)) {
+ BLI_snprintf(r_path, path_len, "%s%s", tmppath, r_name);
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_path);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+{
+ thumbpathname_from_uri(uri, NULL, 0, thumb, thumb_len, THB_FAIL);
}
-static int thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
+static bool thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
{
- char tmppath[FILE_MAX];
- int rv = 0;
-
- if (get_thumb_dir(tmppath, size)) {
- char thumb[40];
- thumbname_from_uri(uri, thumb, sizeof(thumb));
- BLI_snprintf(path, path_len, "%s%s", tmppath, thumb);
- rv = 1;
- }
- return rv;
+ return thumbpathname_from_uri(uri, path, path_len, NULL, 0, size);
}
void IMB_thumb_makedirs(void)
{
char tpath[FILE_MAX];
+#if 0 /* UNUSED */
if (get_thumb_dir(tpath, THB_NORMAL)) {
BLI_dir_create_recursive(tpath);
}
+#endif
+ if (get_thumb_dir(tpath, THB_LARGE)) {
+ BLI_dir_create_recursive(tpath);
+ }
if (get_thumb_dir(tpath, THB_FAIL)) {
BLI_dir_create_recursive(tpath);
}
}
/* create thumbnail for file and returns new imbuf for thumbnail */
-ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+static ImBuf *thumb_create_ex(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source, ImBuf *img)
{
- char uri[URI_MAX] = "";
char desc[URI_MAX + 22];
char tpath[FILE_MAX];
char tdir[FILE_MAX];
@@ -287,7 +319,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
char mtime[40] = "0"; /* in case we can't stat the file */
char cwidth[40] = "0"; /* in case images have no data */
char cheight[40] = "0";
- char thumb[40];
short tsize = 128;
short ex, ey;
float scaledx, scaledy;
@@ -295,10 +326,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
switch (size) {
case THB_NORMAL:
- tsize = 128;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT;
break;
case THB_LARGE:
- tsize = 256;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT * 2;
break;
case THB_FAIL:
tsize = 1;
@@ -309,20 +340,18 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
/* exception, skip images over 100mb */
if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(path);
+ const size_t file_size = BLI_file_size(file_path);
if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
- // printf("file too big: %d, skipping %s\n", (int)size, path);
+ // printf("file too big: %d, skipping %s\n", (int)size, file_path);
return NULL;
}
}
- uri_from_filename(path, uri);
- thumbname_from_uri(uri, thumb, sizeof(thumb));
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
- thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
+// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb);
- if (BLI_path_ncmp(path, tdir, sizeof(tdir)) == 0) {
+ if (BLI_path_ncmp(file_path, tdir, sizeof(tdir)) == 0) {
return NULL;
}
if (size == THB_FAIL) {
@@ -330,20 +359,26 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
if (!img) return NULL;
}
else {
- if (THB_SOURCE_IMAGE == source || THB_SOURCE_BLEND == source) {
-
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
/* only load if we didnt give an image */
if (img == NULL) {
- if (THB_SOURCE_BLEND == source) {
- img = IMB_loadblend_thumb(path);
- }
- else {
- img = IMB_loadiffname(path, IB_rect | IB_metadata, NULL);
+ switch (source) {
+ case THB_SOURCE_IMAGE:
+ img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ break;
+ case THB_SOURCE_BLEND:
+ img = IMB_thumb_load_blend(file_path);
+ break;
+ case THB_SOURCE_FONT:
+ img = IMB_thumb_load_font(file_path, tsize, tsize);
+ break;
+ default:
+ BLI_assert(0); /* This should never happen */
}
}
if (img != NULL) {
- if (BLI_stat(path, &info) != -1) {
+ if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x);
@@ -352,11 +387,11 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
else if (THB_SOURCE_MOVIE == source) {
struct anim *anim = NULL;
- anim = IMB_open_anim(path, IB_rect | IB_metadata, 0, NULL);
+ anim = IMB_open_anim(file_path, IB_rect | IB_metadata, 0, NULL);
if (anim != NULL) {
img = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (img == NULL) {
- printf("not an anim; %s\n", path);
+ printf("not an anim; %s\n", file_path);
}
else {
IMB_freeImBuf(img);
@@ -364,7 +399,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
IMB_free_anim(anim);
}
- if (BLI_stat(path, &info) != -1) {
+ if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
}
@@ -380,7 +415,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
ex = (short)scaledx;
ey = (short)scaledy;
-
+
/* save some time by only scaling byte buf */
if (img->rect_float) {
if (img->rect == NULL) {
@@ -397,7 +432,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
IMB_metadata_change_field(img, "Software", "Blender");
IMB_metadata_change_field(img, "Thumb::URI", uri);
IMB_metadata_change_field(img, "Thumb::MTime", mtime);
- if (THB_SOURCE_IMAGE == source) {
+ if (use_hash) {
+ IMB_metadata_change_field(img, "X-Blender::Hash", hash);
+ }
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth);
IMB_metadata_change_field(img, "Thumb::Image::Height", cheight);
}
@@ -412,12 +450,40 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
BLI_rename(temp, tpath);
}
+ }
+ return img;
+}
- return img;
+static ImBuf *thumb_create_or_fail(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source)
+{
+ ImBuf *img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, size, source, NULL);
+
+ if (!img) {
+ /* thumb creation failed, write fail thumb */
+ img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, THB_FAIL, source, NULL);
+ if (img) {
+ /* we don't need failed thumb anymore */
+ IMB_freeImBuf(img);
+ img = NULL;
+ }
}
+
return img;
}
+ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+{
+ char uri[URI_MAX] = "";
+ char thumb_name[40];
+
+ uri_from_filename(path, uri);
+ thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
+
+ return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, size, source, img);
+}
+
/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
@@ -456,25 +522,30 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
/* create the thumb if necessary and manage failed and old thumbs */
-ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
- char thumb[FILE_MAX];
+ char thumb_path[FILE_MAX];
+ char thumb_name[40];
char uri[URI_MAX];
+ const char *file_path;
+ const char *path;
BLI_stat_t st;
ImBuf *img = NULL;
-
- if (BLI_stat(path, &st) == -1) {
+
+ path = file_path = org_path;
+
+ if (BLI_stat(file_path, &st) == -1) {
return NULL;
}
if (!uri_from_filename(path, uri)) {
return NULL;
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), THB_FAIL)) {
+ if (thumbpath_from_uri(uri, thumb_path, sizeof(thumb_path), THB_FAIL)) {
/* failure thumb exists, don't try recreating */
- if (BLI_exists(thumb)) {
+ if (BLI_exists(thumb_path)) {
/* clear out of date fail case */
- if (BLI_file_older(thumb, path)) {
- BLI_delete(thumb, false, false);
+ if (BLI_file_older(thumb_path, file_path)) {
+ BLI_delete(thumb_path, false, false);
}
else {
return NULL;
@@ -482,52 +553,53 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
}
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
- if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) {
+ if (thumbpathname_from_uri(uri, thumb_path, sizeof(thumb_path), thumb_name, sizeof(thumb_name), size)) {
+ if (BLI_path_ncmp(path, thumb_path, sizeof(thumb_path)) == 0) {
img = IMB_loadiffname(path, IB_rect, NULL);
}
else {
- img = IMB_loadiffname(thumb, IB_rect | IB_metadata, NULL);
+ img = IMB_loadiffname(thumb_path, IB_rect | IB_metadata, NULL);
if (img) {
+ bool regenerate = false;
+
char mtime[40];
- if (!IMB_metadata_get_field(img, "Thumb::MTime", mtime, 40)) {
- /* illegal thumb, forget it! */
- IMB_freeImBuf(img);
- img = NULL;
+ char thumb_hash[33];
+ char thumb_hash_curr[33];
+
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) {
+ regenerate = (st.st_mtime != atol(mtime));
}
else {
- time_t t = atol(mtime);
- if (st.st_mtime != t) {
- /* recreate all thumbs */
- IMB_freeImBuf(img);
- img = NULL;
- IMB_thumb_delete(path, THB_NORMAL);
- IMB_thumb_delete(path, THB_LARGE);
- IMB_thumb_delete(path, THB_FAIL);
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ /* illegal thumb, regenerate it! */
+ regenerate = true;
+ }
+
+ if (use_hash && !regenerate) {
+ if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) {
+ regenerate = !STREQ(thumb_hash, thumb_hash_curr);
+ }
+ else {
+ regenerate = true;
}
}
+
+ if (regenerate) {
+ /* recreate all thumbs */
+ IMB_freeImBuf(img);
+ img = NULL;
+ IMB_thumb_delete(path, THB_NORMAL);
+ IMB_thumb_delete(path, THB_LARGE);
+ IMB_thumb_delete(path, THB_FAIL);
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
+ }
}
else {
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ char thumb_hash[33];
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
}
}
}
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index aee465c49cc..d7b9089c437 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -121,7 +121,7 @@ static ImBuf *loadblend_thumb(gzFile gzfile)
return NULL;
}
-ImBuf *IMB_loadblend_thumb(const char *path)
+ImBuf *IMB_thumb_load_blend(const char *path)
{
gzFile gzfile;
/* not necessarily a gzip */
@@ -143,7 +143,7 @@ ImBuf *IMB_loadblend_thumb(const char *path)
/* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */
#define MARGIN 2
-void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect)
+void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float aspect)
{
unsigned char *px = (unsigned char *)thumb;
int margin_l = MARGIN;
diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c
new file mode 100644
index 00000000000..4b024f3c51b
--- /dev/null
+++ b/source/blender/imbuf/intern/thumbs_font.c
@@ -0,0 +1,100 @@
+/*
+ * ***** 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): Thomas Beck.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/thumbs_font.c
+ * \ingroup imbuf
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_fileops.h"
+#include "BLI_hash_md5.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_thumbs.h"
+
+
+/* XXX, bad level call */
+#include "../../blenfont/BLF_api.h"
+#include "../../blenfont/BLF_translation.h" /* 'N_' macro and BLF_lang_get()... */
+
+static const char *thumb_str[] = {
+ N_("AaBbCc"),
+
+ N_("The quick"),
+ N_("brown fox"),
+ N_("jumps over"),
+ N_("the lazy dog"),
+};
+
+struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y)
+{
+ const int font_size = y / 4;
+
+ struct ImBuf *ibuf;
+ float font_color[4];
+
+ /* create a white image (theme color is used for drawing) */
+ font_color[0] = font_color[1] = font_color[2] = 1.0f;
+
+ /* fill with zero alpha */
+ font_color[3] = 0.0f;
+
+ ibuf = IMB_allocImBuf(x, y, 32, IB_rect | IB_metadata);
+ IMB_rectfill(ibuf, font_color);
+
+ /* draw with full alpha */
+ font_color[3] = 1.0f;
+
+ BLF_thumb_preview(
+ filename, thumb_str, ARRAY_SIZE(thumb_str),
+ font_color, font_size,
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels);
+
+ return ibuf;
+}
+
+bool IMB_thumb_load_font_get_hash(char *r_hash)
+{
+ char buf[1024];
+ char *str = buf;
+ size_t len = 0;
+
+ int draw_str_lines = ARRAY_SIZE(thumb_str);
+ int i;
+
+ unsigned char digest[16];
+
+ len += BLI_strncpy_rlen(str + len, THUMB_DEFAULT_HASH, sizeof(buf) - len);
+
+ for (i = 0; (i < draw_str_lines) && (len < sizeof(buf)); i++) {
+ len += BLI_strncpy_rlen(str + len, BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, thumb_str[i]), sizeof(buf) - len);
+ }
+
+ BLI_hash_md5_buffer(str, len, digest);
+ r_hash[0] = '\0';
+ BLI_hash_md5_to_hexdigest(digest, r_hash);
+
+ return true;
+}
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 4d58642e9c4..62097635296 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -454,7 +454,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (bitspersample == 32) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_fl(fbuf, ibuf->x, 1.0f);
+ copy_vn_fl(fbuf, ibuf->x, 1.0f);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
@@ -464,7 +464,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
else if (bitspersample == 16) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_ushort(sbuf, ibuf->x, 65535);
+ copy_vn_ushort(sbuf, ibuf->x, 65535);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 32100aa2288..8b16e03aed2 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -186,11 +186,13 @@ int IMB_ispic_type(const char *name)
#define HEADER_SIZE 64
unsigned char buf[HEADER_SIZE];
- ImFileType *type;
+ const ImFileType *type;
BLI_stat_t st;
int fp;
- if (UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name);
+ BLI_assert(!BLI_path_is_rel(name));
+
+ if (UTIL_DEBUG) printf("%s: loading %s\n", __func__, name);
if (BLI_stat(name, &st) == -1)
return false;
@@ -389,7 +391,9 @@ int imb_get_anim_type(const char *name)
int type;
BLI_stat_t st;
- if (UTIL_DEBUG) printf("in getanimtype: %s\n", name);
+ BLI_assert(!BLI_path_is_rel(name));
+
+ if (UTIL_DEBUG) printf("%s: %s\n", __func__, name);
#ifndef _WIN32
# ifdef WITH_QUICKTIME
@@ -434,8 +438,20 @@ int imb_get_anim_type(const char *name)
bool IMB_isanim(const char *filename)
{
int type;
-
+
type = imb_get_anim_type(filename);
return (type && type != ANIM_SEQUENCE);
}
+
+bool IMB_isfloat(ImBuf *ibuf)
+{
+ const ImFileType *type;
+
+ for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+ if (type->ftype(type, ibuf)) {
+ return (type->flag & IM_FTYPE_FLOAT) != 0;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 087330d10d2..28710fba823 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -33,6 +33,10 @@
#include <stdio.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -41,26 +45,16 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static ImBuf *prepare_write_imbuf(ImFileType *type, ImBuf *ibuf)
+static ImBuf *prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
{
- ImBuf *write_ibuf = ibuf;
-
- if (type->flag & IM_FTYPE_FLOAT) {
- /* pass */
- }
- else {
- if (ibuf->rect == NULL && ibuf->rect_float) {
- ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
- IMB_rect_from_float(ibuf);
- }
- }
-
- return write_ibuf;
+ return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
}
short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
{
- ImFileType *type;
+ const ImFileType *type;
+
+ BLI_assert(!BLI_path_is_rel(name));
if (ibuf == NULL) return (false);
ibuf->flags = flags;
@@ -86,3 +80,19 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
return false;
}
+ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
+{
+ ImBuf *write_ibuf = ibuf;
+
+ if (isfloat) {
+ /* pass */
+ }
+ else {
+ if (ibuf->rect == NULL && ibuf->rect_float) {
+ ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ return write_ibuf;
+}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index b51b53cc801..f68de03614b 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -155,20 +155,36 @@ typedef struct Library {
enum eIconSizes {
ICON_SIZE_ICON = 0,
- ICON_SIZE_PREVIEW = 1
+ ICON_SIZE_PREVIEW = 1,
+
+ NUM_ICON_SIZES
+};
+
+/* for PreviewImage->flag */
+enum ePreviewImage_Flag {
+ PRV_CHANGED = (1 << 0),
+ PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
};
-#define NUM_ICON_SIZES (ICON_SIZE_PREVIEW + 1)
typedef struct PreviewImage {
/* All values of 2 are really NUM_ICON_SIZES */
unsigned int w[2];
unsigned int h[2];
- short changed[2];
+ short flag[2];
short changed_timestamp[2];
unsigned int *rect[2];
+
+ /* Runtime-only data. */
struct GPUTexture *gputexture[2];
+ int icon_id; /* Used by previews outside of ID context. */
+
+ char pad[3];
+ char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */
} PreviewImage;
+#define PRV_DEFERRED_DATA(prv) \
+ (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1))
+
/**
* Defines for working with IDs.
*
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 7b331181a58..761e76eb249 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -375,7 +375,9 @@ typedef enum ePose_Flags {
/* set by BKE_pose_rebuild to give a chance to the IK solver to rebuild IK tree */
POSE_WAS_REBUILT = (1 << 5),
/* set by game_copy_pose to indicate that this pose is used in the game engine */
- POSE_GAME_ENGINE = (1 << 6)
+ POSE_GAME_ENGINE = (1 << 6),
+ /* pose constraint flags needs to be updated */
+ POSE_CONSTRAINTS_NEED_UPDATE_FLAGS = (1 << 7),
} ePose_Flags;
/* IK Solvers ------------------------------------ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 9e6b71fcbac..68f80cb27d8 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -459,7 +459,7 @@ typedef struct FCurve {
int color_mode; /* coloring method to use (eFCurve_Coloring) */
float color[3]; /* the last-color this curve took */
- float prev_norm_factor, pad;
+ float prev_norm_factor, prev_offset;
} FCurve;
@@ -853,6 +853,8 @@ typedef struct AnimData {
/* nla-tracks */
ListBase nla_tracks;
+ /* active NLA-track (only set/used during tweaking, so no need to worry about dangling pointers) */
+ NlaTrack *act_track;
/* active NLA-strip (only set/used during tweaking, so no need to worry about dangling pointers) */
NlaStrip *actstrip;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 89c8316002b..f83caea66a2 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -137,34 +137,29 @@ typedef struct Brush {
float mask_stencil_dimension[2];
} Brush;
-typedef struct PaletteColor
-{
+typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
float rgb[3];
float value;
} PaletteColor;
-typedef struct Palette
-{
+typedef struct Palette {
ID id;
/* pointer to individual colours */
ListBase colors;
- ListBase deleted;
int active_color;
int pad;
} Palette;
-typedef struct PaintCurvePoint
-{
+typedef struct PaintCurvePoint {
BezTriple bez; /* bezier handle */
float pressure; /* pressure on that point */
} PaintCurvePoint;
-typedef struct PaintCurve
-{
+typedef struct PaintCurve {
ID id;
PaintCurvePoint *points; /* points of curve */
int tot_points;
@@ -260,6 +255,36 @@ typedef enum BrushSculptTool {
SCULPT_TOOL_MASK = 19
} BrushSculptTool;
+/** When #BRUSH_ACCUMULATE is used */
+#define SCULPT_TOOL_HAS_ACCUMULATE(t) ELEM(t, \
+ SCULPT_TOOL_DRAW, \
+ SCULPT_TOOL_CREASE, \
+ SCULPT_TOOL_BLOB, \
+ SCULPT_TOOL_LAYER, \
+ SCULPT_TOOL_INFLATE, \
+ SCULPT_TOOL_CLAY, \
+ SCULPT_TOOL_CLAY_STRIPS, \
+ SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_FLATTEN \
+ )
+
+#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, \
+ SCULPT_TOOL_GRAB, \
+ SCULPT_TOOL_SNAKE_HOOK \
+ )
+
+#define SCULPT_TOOL_HAS_DYNTOPO(t) (ELEM(t, \
+ /* These brushes, as currently coded, cannot support dynamic topology */ \
+ SCULPT_TOOL_GRAB, \
+ SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_THUMB, \
+ SCULPT_TOOL_LAYER, \
+ \
+ /* These brushes could handle dynamic topology, but user feedback indicates it's better not to */ \
+ SCULPT_TOOL_SMOOTH, \
+ SCULPT_TOOL_MASK \
+ ) == 0)
+
/* ImagePaintSettings.tool */
typedef enum BrushImagePaintTool {
PAINT_TOOL_DRAW = 0,
@@ -300,7 +325,7 @@ typedef enum BlurKernelType {
KERNEL_BOX
} BlurKernelType;
-#define MAX_BRUSH_PIXEL_RADIUS 200
+#define MAX_BRUSH_PIXEL_RADIUS 500
#endif
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index c67a356a708..6a9942aea66 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -44,6 +44,16 @@ struct Object;
struct AnimData;
struct Ipo;
+/* ------------------------------------------- */
+/* Stereo Settings */
+typedef struct CameraStereoSettings {
+ float interocular_distance;
+ float convergence_distance;
+ short convergence_mode;
+ short pivot;
+ short pad, pad2;
+} CameraStereoSettings;
+
typedef struct Camera {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -69,6 +79,9 @@ typedef struct Camera {
char sensor_fit;
char pad[7];
+
+ /* Stereo settings */
+ struct CameraStereoSettings stereo;
} Camera;
/* **************** CAMERA ********************* */
@@ -123,6 +136,20 @@ enum {
#define DEFAULT_SENSOR_WIDTH 32.0f
#define DEFAULT_SENSOR_HEIGHT 18.0f
+/* stereo->convergence_mode */
+enum {
+ CAM_S3D_OFFAXIS = 0,
+ CAM_S3D_PARALLEL = 1,
+ CAM_S3D_TOE = 2,
+};
+
+/* stereo->pivot */
+enum {
+ CAM_S3D_PIVOT_LEFT = 0,
+ CAM_S3D_PIVOT_RIGHT = 1,
+ CAM_S3D_PIVOT_CENTER = 2,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index e3731129632..c9a5e056e4a 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -133,7 +133,6 @@ typedef struct Histogram {
float co[2][2];
} Histogram;
-struct ImBuf;
typedef struct Scopes {
int ok;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 288743d5e2f..40c028c3aa1 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -46,7 +46,6 @@ struct Key;
struct Material;
struct VFont;
struct AnimData;
-struct SelBox;
struct EditFont;
struct GHash;
@@ -158,6 +157,7 @@ typedef struct Nurb {
short tilt_interp; /* KEY_LINEAR, KEY_CARDINAL, KEY_BSPLINE */
short radius_interp;
+ /* only used for dynamically generated Nurbs created from OB_FONT's */
int charidx;
} Nurb;
diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h
index 0dd7f37f8b4..0a0d46d70ff 100644
--- a/source/blender/makesdna/DNA_documentation.h
+++ b/source/blender/makesdna/DNA_documentation.h
@@ -48,6 +48,24 @@
* be badly defined. The reason for this is that it is called with
* different types of arguments. It takes a char* at this moment...
*
+ * - Ignoring structs:
+ *
+ * Sometimes we need to define structs in DNA which aren't written
+ * to disk, and can be excluded from blend file DNA string.
+ * in this case, add two '#' chars directly before the struct. eg.
+ *
+ * \code{.c}
+ * #
+ * #
+ * typedef struct MyStruct {
+ * int value;
+ * } MyStruct;
+ * \endcode
+ *
+ * Ignored structs can only be referred to from non-ignored structs
+ * when referred to as a pointer (where they're usually allocated
+ * and cleared in ``readfile.c``).
+ *
* - %Path to the header files
*
* Also because of historical reasons, there is a path prefix to the
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index dece93af122..17553e98817 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -29,7 +29,6 @@
#define __DNA_DYNAMICPAINT_TYPES_H__
#include "DNA_listBase.h"
-struct CurveMapping;
struct PaintSurfaceData;
/* surface format */
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index b6009b3f899..967cb7284dc 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -38,6 +38,8 @@ typedef struct GPUDOFSettings {
float fstop;
float focal_length;
float sensor;
+ int num_blades;
+ int high_quality;
} GPUDOFSettings;
/* properties for SSAO effect */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index dca1c8330b0..0e2a41a0aeb 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -39,12 +39,10 @@
struct PackedFile;
struct Scene;
struct anim;
-struct ImBuf;
struct MovieCache;
struct RenderResult;
struct GPUTexture;
-
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
typedef struct ImageUser {
@@ -54,16 +52,32 @@ typedef struct ImageUser {
int frames; /* total amount of frames to use */
int offset, sfra; /* offset within movie, start frame in global time */
char fie_ima, cycl; /* fields/image in movie, cyclic flag */
- char ok, pad;
+ char ok;
- short multi_index, layer, pass; /* listbase indices, for menu browsing or retrieve buffer */
+ char multiview_eye; /* multiview current eye - for internal use of drawing routines */
+ int passtype;
+ short multi_index, view, layer; /* listbase indices, for menu browsing or retrieve buffer */
short flag;
-
- int pad2;
-
} ImageUser;
+typedef struct ImageAnim {
+ struct ImageAnim *next, *prev;
+ struct anim *anim;
+} ImageAnim;
+
+typedef struct ImageView {
+ struct ImageView *next, *prev;
+ char name[64]; /* MAX_NAME */
+ char filepath[1024]; /* 1024 = FILE_MAX */
+} ImageView;
+
+typedef struct ImagePackedFile {
+ struct ImagePackedFile *next, *prev;
+ struct PackedFile *packedfile;
+ char filepath[1024]; /* 1024 = FILE_MAX */
+} ImagePackedFile;
+
typedef struct RenderSlot {
char name[64]; /* 64 = MAX_NAME */
} RenderSlot;
@@ -73,6 +87,7 @@ typedef struct RenderSlot {
#define IMA_ANIM_REFRESHED 2
/* #define IMA_DO_PREMUL 4 */
#define IMA_NEED_FRAME_RECALC 8
+#define IMA_SHOW_STEREO 16
typedef struct Image {
ID id;
@@ -83,13 +98,13 @@ typedef struct Image {
struct GPUTexture *gputexture; /* not written in file */
/* sources from: */
- struct anim *anim;
+ ListBase anims;
struct RenderResult *rr;
struct RenderResult *renders[8]; /* IMA_MAX_RENDER_SLOT */
short render_slot, last_render_slot;
-
- short ok, flag;
+
+ int flag;
short source, type;
int lastframe;
@@ -100,14 +115,16 @@ typedef struct Image {
unsigned int bindcode; /* only for current image... */
unsigned int *repbind; /* for repeat of parts of images */
- struct PackedFile *packedfile;
+ struct PackedFile *packedfile DNA_DEPRECATED; /* deprecated */
+ struct ListBase packedfiles;
struct PreviewImage *preview;
/* game engine tile animation */
float lastupdate;
int lastused;
short animspeed;
- short pad2;
+
+ short ok;
/* for generated images */
int gen_x, gen_y;
@@ -122,7 +139,14 @@ typedef struct Image {
ColorManagedColorspaceSettings colorspace_settings;
char alpha_mode;
- char pad[7];
+ char pad[5];
+
+ /* Multiview */
+ char eye; /* for viewer node stereoscopy */
+ char views_format;
+ ListBase views;
+ struct Stereo3dFormat *stereo3d_format;
+
RenderSlot render_slots[8]; /* 8 = IMA_MAX_RENDER_SLOT */
} Image;
@@ -144,6 +168,9 @@ enum {
IMA_VIEW_AS_RENDER = (1 << 11),
IMA_IGNORE_ALPHA = (1 << 12),
IMA_DEINTERLACE = (1 << 13),
+ IMA_USE_VIEWS = (1 << 14),
+ IMA_IS_STEREO = (1 << 15),
+ IMA_IS_MULTIVIEW = (1 << 16), /* similar to stereo, but a more general case */
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index a920182d5a3..ce8e86cb512 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -151,6 +151,7 @@ typedef struct Lamp {
#define LA_LAYER_SHADOW (1 << 15)
#define LA_SHAD_TEX (1 << 16)
#define LA_SHOW_CONE (1 << 17)
+#define LA_SHOW_SHADOW_BOX (1 << 18)
/* layer_shadow */
#define LA_LAYER_SHADOW_BOTH 0
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 8067fa5db2d..3799de011d4 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -37,7 +37,6 @@
#include "DNA_customdata_types.h"
struct AnimData;
-struct DerivedMesh;
struct Ipo;
struct Key;
struct MCol;
@@ -47,13 +46,11 @@ struct MLoop;
struct MLoopCol;
struct MLoopUV;
struct MPoly;
-struct MSticky;
struct MTexPoly;
struct MVert;
struct Material;
struct Mesh;
struct Multires;
-struct OcInfo;
typedef struct Mesh {
ID id;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 3304980f964..b76f40c884d 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -35,7 +35,6 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
-struct Bone;
struct Image;
/*tessellation face, see MLoop/MPoly for the real face data*/
@@ -216,7 +215,6 @@ typedef struct MultiresEdge {
unsigned int mid;
} MultiresEdge;
-struct MultiresMapNode;
typedef struct MultiresLevel {
struct MultiresLevel *next, *prev;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index b32b228fda4..1fc66b9b016 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -84,6 +84,7 @@ typedef enum ModifierType {
eModifierType_Wireframe = 48,
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
+ eModifierType_CorrectiveSmooth = 51,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -430,10 +431,11 @@ typedef struct DecimateModifierData {
float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */
char defgrp_name[64]; /* MAX_VGROUP_NAME */
+ float defgrp_factor;
short flag, mode;
/* runtime only */
- int face_count, pad2;
+ int face_count;
} DecimateModifierData;
enum {
@@ -1288,6 +1290,48 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+
+typedef struct CorrectiveSmoothModifierData {
+ ModifierData modifier;
+
+ /* positions set during 'bind' operator
+ * use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
+ float (*bind_coords)[3];
+
+ /* note: -1 is used to bind */
+ unsigned int bind_coords_num;
+
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char pad[2];
+
+ char defgrp_name[64]; /* MAX_VGROUP_NAME */
+
+ /* runtime-only cache (delta's between),
+ * delta's between the original positions and the smoothed positions */
+ float (*delta_cache)[3];
+ unsigned int delta_cache_num;
+ char pad2[4];
+} CorrectiveSmoothModifierData;
+
+enum {
+ MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE = 0,
+ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT = 1,
+};
+
+enum {
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO = 0,
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
+};
+
+/* Corrective Smooth modifier flags */
+enum {
+ MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
+ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
+ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY = (1 << 2),
+};
+
typedef struct UVWarpModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index f08b3ea9590..bce13921903 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -40,7 +40,6 @@
struct ID;
struct ListBase;
-struct SpaceNode;
struct bNodeLink;
struct bNodeType;
struct bNodeTreeExec;
@@ -264,12 +263,12 @@ typedef struct bNode {
*/
#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
+#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
/* Unique hash key for identifying node instances
* Defined as a struct because DNA does not support other typedefs.
*/
-typedef struct bNodeInstanceKey
-{
+typedef struct bNodeInstanceKey {
unsigned int value;
} bNodeInstanceKey;
@@ -383,10 +382,12 @@ typedef struct bNodeTree {
/* callbacks */
void (*progress)(void *, float progress);
- void (*stats_draw)(void *, char *str);
+ void (*stats_draw)(void *, const char *str);
int (*test_break)(void *);
void (*update_draw)(void *);
void *tbh, *prh, *sdh, *udh;
+
+ void *duplilock;
} bNodeTree;
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index 5cc56d861a3..c9c1f618e86 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -297,7 +297,7 @@ typedef struct SoftBody {
char namedVG_Softgoal[64]; /* MAX_VGROUP_NAME */
/* starting to fix old bug .. nastiness that VG are indexes
* rather find them by name tag to find it -> jow20090613 */
-
+
short fuzzyness; /* */
/* springs */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 2699bb5f22f..2daba6a3f0d 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -48,7 +48,6 @@ struct Ipo;
struct BoundBox;
struct Path;
struct Material;
-struct bConstraintChannel;
struct PartDeflect;
struct SoftBody;
struct FluidsimSettings;
@@ -109,7 +108,8 @@ typedef struct LodLevel {
struct LodLevel *next, *prev;
struct Object *source;
int flags;
- float distance;
+ float distance, pad;
+ int obhysteresis;
} LodLevel;
typedef struct Object {
@@ -191,7 +191,8 @@ typedef struct Object {
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
- int pad;
+ /* did last modifier stack generation need mapping support? */
+ int lastNeedMapping;
/* during realtime */
@@ -213,6 +214,8 @@ typedef struct Object {
float margin;
float max_vel; /* clamp the maximum velocity 0.0 is disabled */
float min_vel; /* clamp the minimum velocity 0.0 is disabled */
+ float max_angvel; /* clamp the maximum angular velocity, 0.0 is disabled */
+ float min_angvel; /* clamp the minimum angular velocity, 0.0 is disabled */
float obstacleRad;
/* "Character" physics properties */
@@ -377,8 +380,8 @@ enum {
enum {
PARTYPE = (1 << 4) - 1,
PAROBJECT = 0,
- PARCURVE = 1,
- PARKEY = 2,
+ PARCURVE = 1, /* Deprecated. */
+ PARKEY = 2, /* XXX Unused, deprecated? */
PARSKEL = 4,
PARVERT1 = 5,
@@ -397,7 +400,7 @@ enum {
OB_DUPLIVERTS = 1 << 4,
OB_DUPLIROT = 1 << 5,
OB_DUPLINOSPEED = 1 << 6,
-/* OB_POWERTRACK = 1 << 7,*/ /*UNUSED*/
+ OB_DUPLICALCDERIVED = 1 << 7, /* runtime, calculate derivedmesh for dupli before it's used */
OB_DUPLIGROUP = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
@@ -484,6 +487,7 @@ enum {
enum {
OB_LOD_USE_MESH = 1 << 0,
OB_LOD_USE_MAT = 1 << 1,
+ OB_LOD_USE_HYST = 1 << 2,
};
@@ -529,7 +533,7 @@ enum {
#define OB_MAX_STATES 30
/* collision masks */
-#define OB_MAX_COL_MASKS 8
+#define OB_MAX_COL_MASKS 16
/* ob->gameflag */
enum {
diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h
index ef0a0f642d6..56140c84cb1 100644
--- a/source/blender/makesdna/DNA_packedFile_types.h
+++ b/source/blender/makesdna/DNA_packedFile_types.h
@@ -40,8 +40,7 @@ typedef struct PackedFile {
void *data;
} PackedFile;
-enum PF_FileStatus
-{
+enum PF_FileStatus {
PF_EQUAL = 0,
PF_DIFFERS = 1,
PF_NOFILE = 2,
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 0eae50a2562..397751d85e9 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -47,6 +47,7 @@ extern "C" {
#include "DNA_ID.h"
#include "DNA_freestyle_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_userdef_types.h"
struct CurveMapping;
struct Object;
@@ -249,6 +250,73 @@ typedef enum ScenePassType {
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
+/* View - MultiView */
+typedef struct SceneRenderView {
+ struct SceneRenderView *next, *prev;
+
+ char name[64]; /* MAX_NAME */
+ char suffix[64]; /* MAX_NAME */
+
+ int viewflag;
+ int pad[2];
+ char pad2[4];
+
+} SceneRenderView;
+
+/* srv->viewflag */
+#define SCE_VIEW_DISABLE (1<<0)
+
+/* scene.render.views_format */
+enum {
+ SCE_VIEWS_FORMAT_STEREO_3D = 0,
+ SCE_VIEWS_FORMAT_MULTIVIEW = 1,
+};
+
+/* ImageFormatData.views_output */
+enum {
+ R_IMF_VIEWS_INDIVIDUAL = 0,
+ R_IMF_VIEWS_STEREO_3D = 1,
+ R_IMF_VIEWS_MULTIVIEW = 2,
+};
+
+typedef struct Stereo3dFormat {
+ short flag;
+ char display_mode; /* encoding mode */
+ char anaglyph_type; /* anaglyph scheme for the user display */
+ char interlace_type; /* interlace type for the user display */
+ char pad[3];
+} Stereo3dFormat;
+
+/* Stereo3dFormat.display_mode */
+typedef enum eStereoDisplayMode {
+ S3D_DISPLAY_ANAGLYPH = 0,
+ S3D_DISPLAY_INTERLACE = 1,
+ S3D_DISPLAY_PAGEFLIP = 2,
+ S3D_DISPLAY_SIDEBYSIDE = 3,
+ S3D_DISPLAY_TOPBOTTOM = 4,
+} eStereoDisplayMode;
+
+/* Stereo3dFormat.flag */
+typedef enum eStereo3dFlag {
+ S3D_INTERLACE_SWAP = (1 << 0),
+ S3D_SIDEBYSIDE_CROSSEYED = (1 << 1),
+ S3D_SQUEEZED_FRAME = (1 << 2),
+} eStereo3dFlag;
+
+/* Stereo3dFormat.anaglyph_type */
+typedef enum eStereo3dAnaglyphType {
+ S3D_ANAGLYPH_REDCYAN = 0,
+ S3D_ANAGLYPH_GREENMAGENTA = 1,
+ S3D_ANAGLYPH_YELLOWBLUE = 2,
+} eStereo3dAnaglyphType;
+
+/* Stereo3dFormat.interlace_type */
+typedef enum eStereo3dInterlaceType {
+ S3D_INTERLACE_ROW = 0,
+ S3D_INTERLACE_COLUMN = 1,
+ S3D_INTERLACE_CHECKERBOARD = 2,
+} eStereo3dInterlaceType;
+
/* *************************************************************** */
/* Generic image format settings,
@@ -286,7 +354,11 @@ typedef struct ImageFormatData {
char jp2_flag;
char jp2_codec;
- char pad[6];
+ char pad[5];
+
+ /* Multiview */
+ char views_format;
+ Stereo3dFormat stereo3d_format;
/* color management */
ColorManagedViewSettings view_settings;
@@ -585,8 +657,10 @@ typedef struct RenderData {
/* render simplify */
int simplify_flag;
short simplify_subsurf;
- short simplify_shadowsamples;
+ short simplify_subsurf_render;
+ short simplify_shadowsamples, pad9;
float simplify_particles;
+ float simplify_particles_render;
float simplify_aosss;
/* cineon */
@@ -615,7 +689,19 @@ typedef struct RenderData {
struct BakeData bake;
int preview_start_resolution;
- int pad;
+
+ /* Type of the debug pass to use.
+ * Only used when built with debug passes support.
+ */
+ short debug_pass_type;
+
+ short pad;
+
+ /* MultiView */
+ ListBase views;
+ short actview;
+ short views_format;
+ short pad8[2];
} RenderData;
/* *************************************************************** */
@@ -718,7 +804,12 @@ typedef struct GameData {
short obstacleSimulation;
short raster_storage;
float levelHeight;
- float deactivationtime, lineardeactthreshold, angulardeactthreshold, pad2;
+ float deactivationtime, lineardeactthreshold, angulardeactthreshold;
+
+ /* Scene LoD */
+ short lodflag, pad2;
+ int scehysteresis, pad5;
+
} GameData;
#define STEREO_NOSTEREO 1
@@ -791,6 +882,9 @@ enum {
#pragma GCC poison GAME_MAT_TEXFACE
#endif
+/* GameData.lodflag */
+#define SCE_LOD_USE_HYST (1 << 0)
+
/* UV Paint */
#define UV_SCULPT_LOCK_BORDERS 1
#define UV_SCULPT_ALL_ISLANDS 2
@@ -802,6 +896,19 @@ enum {
#define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1
#define UV_SCULPT_TOOL_RELAX_HC 2
+/* Stereo Flags */
+#define STEREO_RIGHT_NAME "right"
+#define STEREO_LEFT_NAME "left"
+#define STEREO_RIGHT_SUFFIX "_R"
+#define STEREO_LEFT_SUFFIX "_L"
+
+typedef enum StereoViews {
+ STEREO_LEFT_ID = 0,
+ STEREO_RIGHT_ID = 1,
+ STEREO_3D_ID = 2,
+ STEREO_MONO_ID = 3,
+} StereoViews;
+
/* Markers */
typedef struct TimeMarker {
@@ -920,6 +1027,8 @@ typedef struct Sculpt {
/* scale for constant detail size */
float constant_detail;
+ float detail_percent;
+ float pad;
struct Object *gravity_object;
void *pad2;
@@ -1170,7 +1279,11 @@ typedef struct ToolSettings {
short snap_flag, snap_target;
short proportional, prop_mode;
char proportional_objects; /* proportional edit, object mode */
- char proportional_mask; /* proportional edit, object mode */
+ char proportional_mask; /* proportional edit, mask editing */
+ char proportional_action; /* proportional edit, action editor */
+ char proportional_fcurve; /* proportional edit, graph editor */
+ char lock_markers; /* lock marker editing */
+ char pad4[5];
char auto_normalize; /*auto normalizing mode in wpaint*/
char multipaint; /* paint multiple bones in wpaint */
@@ -1287,13 +1400,15 @@ typedef struct Scene {
ListBase transform_spaces;
void *sound_scene;
- void *sound_scene_handle;
+ void *playback_handle;
void *sound_scrub_handle;
void *speaker_handles;
void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */
/* none of the dependency graph vars is mean to be saved */
+ struct Depsgraph *depsgraph;
+ void *pad1;
struct DagForest *theDag;
short dagflags;
short recalc; /* recalc = counterpart of ob->recalc */
@@ -1432,6 +1547,7 @@ typedef struct Scene {
#define R_TEXNODE_PREVIEW 0x40000
#define R_VIEWPORT_PREVIEW 0x80000
#define R_EXR_CACHE_FILE 0x100000
+#define R_MULTIVIEW 0x200000
/* r->stamp */
#define R_STAMP_TIME 0x0001
@@ -1745,7 +1861,8 @@ typedef enum SculptFlags {
SCULPT_DYNTOPO_COLLAPSE = (1 << 11),
/* If set, dynamic-topology detail size will be constant in object space */
- SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13)
+ SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13),
+ SCULPT_DYNTOPO_DETAIL_BRUSH = (1 << 14),
} SculptFlags;
typedef enum ImagePaintMode {
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 3e02071c3dd..eb76c90c0fc 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -41,7 +41,6 @@ struct SpaceLink;
struct ARegion;
struct ARegionType;
struct PanelType;
-struct HeaderType;
struct Scene;
struct uiLayout;
struct wmTimer;
@@ -282,6 +281,8 @@ enum {
AREA_FLAG_TEMP_TYPE = (1 << 6),
/* for temporary fullscreens (file browser, image editor render) that are opened above user set fullscreens */
AREA_FLAG_STACKED_FULLSCREEN = (1 << 7),
+ /* update action zones (even if the mouse is not intersecting them) */
+ AREA_FLAG_ACTIONZONES_UPDATE = (1 << 8),
};
#define EDGEWIDTH 1
@@ -373,6 +374,8 @@ enum {
RGN_TYPE_TOOL_PROPS = 6,
RGN_TYPE_PREVIEW = 7
};
+/* use for function args */
+#define RGN_TYPE_ANY -1
/* region alignment */
#define RGN_ALIGN_NONE 0
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index 8d59a13768b..d886dcf2807 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -164,7 +164,7 @@ typedef struct bSensor {
struct bSensor *next, *prev;
/* pulse and freq are the bool toggle and frame count for pulse mode */
short type, otype, flag, pulse;
- short freq, totlinks, pad1, pad2;
+ short freq, totlinks, pad1, pad2; /* freq makes reference to skipped ticks between 2 active pulses */
char name[64]; /* MAX_NAME */
void *data;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index c6748cca8e1..76c27fd3547 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -53,6 +53,11 @@ struct MovieClip;
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
+typedef struct StripAnim {
+ struct StripAnim *next, *prev;
+ struct anim *anim;
+} StripAnim;
+
typedef struct StripElem {
char name[256];
int orig_width, orig_height;
@@ -95,7 +100,8 @@ typedef struct StripProxy {
short build_tc_flags; // time code flags (see below) of all tc indices
// to build
short build_flags;
- char pad[6];
+ char storage;
+ char pad[5];
} StripProxy;
typedef struct Strip {
@@ -155,8 +161,7 @@ typedef struct Sequence {
struct Object *scene_camera; /* override scene camera */
struct MovieClip *clip; /* for MOVIECLIP strips */
struct Mask *mask; /* for MASK strips */
-
- struct anim *anim; /* for MOVIE strips */
+ ListBase anims; /* for MOVIE strips */
float effect_fader;
float speed_fader;
@@ -186,7 +191,13 @@ typedef struct Sequence {
int sfra; /* starting frame according to the timeline of the scene. */
char alpha_mode;
- char pad[3];
+ char pad[2];
+
+ /* Multiview */
+ char views_format;
+ struct Stereo3dFormat *stereo3d_format;
+
+ struct IDProperty *prop;
/* modifiers */
ListBase modifiers;
@@ -209,9 +220,10 @@ typedef struct Editing {
Sequence *act_seq;
char act_imagedir[1024]; /* 1024 = FILE_MAX */
char act_sounddir[1024]; /* 1024 = FILE_MAX */
+ char proxy_dir[1024]; /* 1024 = FILE_MAX */
int over_ofs, over_cfra;
- int over_flag, pad;
+ int over_flag, proxy_storage;
rctf over_border;
} Editing;
@@ -326,6 +338,10 @@ typedef struct SequencerScopes {
#define SEQ_STRIP_OFSBOTTOM 0.2f
#define SEQ_STRIP_OFSTOP 0.8f
+/* Editor->proxy_storage */
+/* store proxies in project directory */
+#define SEQ_EDIT_PROXY_DIR_STORAGE 1
+
/* SpeedControlVars->flags */
#define SEQ_SPEED_INTEGRATE 1
/* #define SEQ_SPEED_BLEND 2 */ /* DEPRECATED */
@@ -354,9 +370,9 @@ enum {
SEQ_USE_TRANSFORM = (1 << 16),
SEQ_USE_CROP = (1 << 17),
/* SEQ_USE_COLOR_BALANCE = (1 << 18), */ /* DEPRECATED */
- SEQ_USE_PROXY_CUSTOM_DIR = (1 << 19),
+ /* SEQ_USE_PROXY_CUSTOM_DIR = (1 << 19), */ /* DEPRECATED */
- SEQ_USE_PROXY_CUSTOM_FILE = (1 << 21),
+ /* SEQ_USE_PROXY_CUSTOM_FILE = (1 << 21), */ /* DEPRECATED */
SEQ_USE_EFFECT_DEFAULT_FADE = (1 << 22),
SEQ_USE_LINEAR_MODIFIERS = (1 << 23),
@@ -368,10 +384,17 @@ enum {
/* don't include Grease Pencil in OpenGL previews of Scene strips */
SEQ_SCENE_NO_GPENCIL = (1 << 28),
+ SEQ_USE_VIEWS = (1 << 29),
SEQ_INVALID_EFFECT = (1 << 31),
};
+/* StripProxy->storage */
+enum {
+ SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
+ SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
+};
+
#if (DNA_DEPRECATED_GCC_POISON == 1)
#pragma GCC poison SEQ_MAKE_PREMUL
#endif
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index cb132c1b550..811d78d67c2 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -41,7 +41,6 @@
struct Ipo;
struct PackedFile;
-struct SpaceLink;
typedef struct bSound {
ID id;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 69affc74ed7..9d5b6bb42b4 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -50,28 +50,21 @@
struct ID;
struct Text;
struct Script;
-struct bSound;
-struct ImBuf;
struct Image;
struct Scopes;
struct Histogram;
struct SpaceIpo;
-struct BlendHandle;
struct bNodeTree;
-struct uiBlock;
struct FileList;
struct bGPdata;
struct bDopeSheet;
struct FileSelectParams;
struct FileLayout;
-struct bScreen;
-struct Scene;
struct wmOperator;
struct wmTimer;
struct MovieClip;
struct MovieClipScopes;
struct Mask;
-struct GHash;
struct BLI_mempool;
@@ -297,10 +290,13 @@ typedef enum eSpaceOutliner_Mode {
/* SpaceOops->storeflag */
typedef enum eSpaceOutliner_StoreFlag {
- /* rebuild tree */
+ /* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
/* if set, it allows redraws. gets set for some allqueue events */
SO_TREESTORE_REDRAW = (1 << 1),
+ /* rebuild the tree, similar to cleanup,
+ * but defer a call to BKE_outliner_treehash_rebuild_from_treestore instead */
+ SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
/* outliner search flags (SpaceOops->search_flags) */
@@ -507,6 +503,9 @@ typedef struct SpaceSeq {
struct bGPdata *gpd; /* grease-pencil data */
struct SequencerScopes scopes; /* different scoped displayed in space */
+
+ char multiview_eye; /* multiview current eye - for internal use */
+ char pad2[7];
} SpaceSeq;
@@ -538,6 +537,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_ALL_WAVEFORMS = (1 << 7), /* draw all waveforms */
SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */
SEQ_SHOW_SAFE_CENTER = (1 << 9),
+ SEQ_SHOW_METADATA = (1 << 10),
} eSpaceSeq_Flag;
/* sseq->view */
@@ -558,8 +558,7 @@ typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_PROXY_RENDER_SIZE_FULL = 100
} eSpaceSeq_Proxy_RenderSize;
-typedef struct MaskSpaceInfo
-{
+typedef struct MaskSpaceInfo {
/* **** mask editing **** */
struct Mask *mask;
/* draw options */
@@ -592,9 +591,12 @@ typedef struct FileSelectParams {
char filter_search[64]; /* text items' name must match to be shown. */
- int active_file;
+ int active_file; /* active file used for keyboard navigation */
+ int highlight_file; /* file under cursor */
int sel_first;
int sel_last;
+ unsigned short thumbnail_size;
+ short pad;
/* short */
short type; /* XXXXX for now store type here, should be moved to the operator */
@@ -717,7 +719,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_FTFONT = (1 << 7),
FILE_TYPE_SOUND = (1 << 8),
FILE_TYPE_TEXT = (1 << 9),
- FILE_TYPE_MOVIE_ICON = (1 << 10), /* movie file that preview can't load */
+ /* 1 << 10 was FILE_TYPE_MOVIE_ICON, got rid of this so free slot for future type... */
FILE_TYPE_FOLDER = (1 << 11), /* represents folders for filtering */
FILE_TYPE_BTX = (1 << 12),
FILE_TYPE_COLLADA = (1 << 13),
@@ -839,6 +841,7 @@ typedef enum eSpaceImage_Flag {
SI_COLOR_CORRECTION = (1 << 24),
SI_NO_DRAW_TEXPAINT = (1 << 25),
+ SI_DRAW_METADATA = (1 << 26)
} eSpaceImage_Flag;
/* Text Editor ============================================ */
@@ -1162,6 +1165,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_GRAPH_SEL_ONLY = (1 << 19),
SC_SHOW_GRAPH_HIDDEN = (1 << 20),
SC_SHOW_GRAPH_TRACKS_ERROR = (1 << 21),
+ SC_SHOW_METADATA = (1 << 22),
} eSpaceClip_Flag;
/* SpaceClip->mode */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index c471cb26892..9888b735b8b 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -43,11 +43,9 @@
/* match-moving data */
struct bGPdata;
-struct ImBuf;
struct Image;
struct MovieReconstructedCamera;
struct MovieTrackingCamera;
-struct MovieTrackingBundle;
struct MovieTrackingMarker;
struct MovieTrackingTrack;
struct MovieTracking;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index afa1f03a8ca..3a0e346d0c8 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -338,6 +338,9 @@ typedef struct ThemeSpace {
char paint_curve_pivot[4];
char paint_curve_handle[4];
+
+ char metadatabg[4];
+ char metadatatext[4];
} ThemeSpace;
@@ -487,8 +490,10 @@ typedef struct UserDef {
short dragthreshold;
int memcachelimit;
int prefetchframes;
+ float pad_rot_angle; /* control the rotation step of the view when PAD2, PAD4, PAD6&PAD8 is use */
+ float pad3;
short frameserverport;
- short pad_rot_angle; /* control the rotation step of the view when PAD2, PAD4, PAD6&PAD8 is use */
+ short pad4;
short obcenter_dia;
short rvisize; /* rotating view icon size */
short rvibright; /* rotating view icon brightness */
@@ -500,7 +505,10 @@ typedef struct UserDef {
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
- char pad1;
+ char view_frame_type;
+
+ int view_frame_keyframes; /* number of keyframes to zoom around current frame */
+ float view_frame_seconds; /* seconds to zoom around current frame */
short scrcastfps; /* frame rate for screencast to be played back */
short scrcastwait; /* milliseconds between screencast snapshots */
@@ -683,6 +691,13 @@ typedef enum eAutokey_Mode {
AUTOKEY_MODE_EDITKEYS = 5
} eAutokey_Mode;
+/* Zoom to frame mode */
+typedef enum eZoomFrame_Mode {
+ ZOOM_FRAME_MODE_KEEP_RANGE = 0,
+ ZOOM_FRAME_MODE_SECONDS = 1,
+ ZOOM_FRAME_MODE_KEYFRAMES = 2
+} eZoomFrame_Mode;
+
/* Auto-Keying flag
* U.autokey_flag (not strictly used when autokeying only - is also used when keyframing these days)
* note: AUTOKEY_FLAG_* is used with a macro, search for lines like IS_AUTOKEY_FLAG(INSERTAVAIL)
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index a7921be44d5..6f2e347c84d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -43,7 +43,7 @@ typedef struct View2D {
rcti mask; /* mask - region (in screenspace) within which 'cur' can be viewed */
float min[2], max[2]; /* min/max sizes of 'cur' rect (only when keepzoom not set) */
- float minzoom, maxzoom; /* self explanatory. allowable zoom factor range (only when keepzoom set) */
+ float minzoom, maxzoom; /* allowable zoom factor range (only when (keepzoom & V2D_LIMITZOOM)) is set */
short scroll; /* scroll - scrollbars to display (bitflag) */
short scroll_ui; /* scroll_ui - temp settings used for UI drawing of scrollers */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 210deddc854..a0516590d43 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -35,9 +35,7 @@
struct ViewDepths;
struct Object;
struct Image;
-struct Tex;
struct SpaceLink;
-struct Base;
struct BoundBox;
struct MovieClip;
struct MovieClipUser;
@@ -217,8 +215,10 @@ typedef struct View3D {
/* drawflags, denoting state */
char zbuf, transp, xray;
+ char multiview_eye; /* multiview current eye - for internal use */
+
/* built-in shader effects (eGPUFXFlags) */
- char pad3[5];
+ char pad3[4];
/* note, 'fx_settings.dof' is currently _not_ allocated,
* instead set (temporarily) from camera */
@@ -230,9 +230,21 @@ typedef struct View3D {
/* XXX deprecated? */
struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */
+ /* multiview - stereo 3d */
+ short stereo3d_flag;
+ char stereo3d_camera;
+ char pad4;
+ float stereo3d_convergence_factor;
+ float stereo3d_volume_alpha;
+ float stereo3d_convergence_alpha;
} View3D;
+/* View3D->stereo_flag (short) */
+#define V3D_S3D_DISPCAMERAS (1 << 0)
+#define V3D_S3D_DISPPLANE (1 << 1)
+#define V3D_S3D_DISPVOLUME (1 << 2)
+
/* View3D->flag (short) */
/*#define V3D_DISPIMAGE 1*/ /*UNUSED*/
#define V3D_DISPBGPICS 2
@@ -367,6 +379,9 @@ enum {
#define RV3D_CAMZOOM_MIN -30
#define RV3D_CAMZOOM_MAX 600
-#endif
+/* #BKE_screen_view3d_zoom_to_fac() values above */
+#define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f
+#define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f
+#endif
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 1a0562ae8c5..51ed8bb6c0d 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,6 +33,7 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_ID.h"
@@ -49,16 +50,14 @@ struct wmKeyConfig;
/* forwards */
struct bContext;
-struct wmLocal;
struct bScreen;
-struct uiBlock;
struct wmSubWindow;
struct wmTimer;
-struct StructRNA;
struct PointerRNA;
struct ReportList;
struct Report;
struct uiLayout;
+struct Stereo3dFormat;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
@@ -209,7 +208,7 @@ typedef struct wmWindow {
struct wmIMEData *ime_data;
int drawmethod, drawfail; /* internal for wm_draw.c only */
- void *drawdata; /* internal for wm_draw.c only */
+ ListBase drawdata; /* internal for wm_draw.c only */
ListBase queue; /* all events (ghost level events were handled) */
ListBase handlers; /* window+screen handlers, handled last */
@@ -217,6 +216,8 @@ typedef struct wmWindow {
ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */
ListBase gesture; /* gesture stuff */
+
+ struct Stereo3dFormat *stereo3d_format; /* properties for stereoscopic displays */
} wmWindow;
#ifdef ime_data
@@ -389,10 +390,16 @@ enum {
/* wmOperator flag */
enum {
- OP_GRAB_POINTER = (1 << 0),
/* low level flag so exec() operators can tell if they were invoked, use with care.
* typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */
- OP_IS_INVOKE = (1 << 1),
+ OP_IS_INVOKE = (1 << 0),
+
+ /* When the cursor is grabbed */
+ OP_IS_MODAL_GRAB_CURSOR = (1 << 1),
+
+ /* allow modal operators to have the region under the cursor for their context
+ * (the regiontype is maintained to prevent errors) */
+ OP_IS_MODAL_CURSOR_REGION = (1 << 2),
};
#endif /* __DNA_WINDOWMANAGER_TYPES_H__ */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 08d2f93866a..be097c0e51e 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -74,7 +74,7 @@ set(INC_SYS
set(SRC
dna_genfile.c
- dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
${SRC_DNA_INC}
)
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 4615a1ce9e4..389e22b2a0c 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -525,7 +525,7 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
for (nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
- BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], (void *)(nr + 1));
+ BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr + 1));
}
#endif
}
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 7f3e9b7c196..a7ff4244d5f 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -539,6 +539,11 @@ static void *read_file_data(char *filename, int *r_len)
*r_len = ftell(fp);
fseek(fp, 0L, SEEK_SET);
+ if (*r_len == -1) {
+ fclose(fp);
+ return NULL;
+ }
+
data = MEM_mallocN(*r_len, "read_file_data");
if (!data) {
*r_len = -1;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 577f27f564e..965d1d91614 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -172,6 +172,7 @@ extern StructRNA RNA_CompositorNodeSepYCCA;
extern StructRNA RNA_CompositorNodeSepYUVA;
extern StructRNA RNA_CompositorNodeSetAlpha;
extern StructRNA RNA_CompositorNodeSplitViewer;
+extern StructRNA RNA_CompositorNodeSwitchView;
extern StructRNA RNA_CompositorNodeTexture;
extern StructRNA RNA_CompositorNodeTime;
extern StructRNA RNA_CompositorNodeTonemap;
@@ -202,6 +203,7 @@ extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
extern StructRNA RNA_DelaySensor;
+extern StructRNA RNA_CorrectiveSmoothModifier;
extern StructRNA RNA_DisplaceModifier;
extern StructRNA RNA_DisplaySafeAreas;
extern StructRNA RNA_DistortedNoiseTexture;
@@ -278,6 +280,7 @@ extern StructRNA RNA_IKParam;
extern StructRNA RNA_Image;
extern StructRNA RNA_ImageFormatSettings;
extern StructRNA RNA_ImagePaint;
+extern StructRNA RNA_ImagePreview;
extern StructRNA RNA_ImageSequence;
extern StructRNA RNA_ImageTexture;
extern StructRNA RNA_ImageUser;
@@ -565,6 +568,7 @@ extern StructRNA RNA_SpeedControlSequence;
extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
extern StructRNA RNA_SpotLamp;
+extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringProperty;
extern StructRNA RNA_Struct;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 4d836601ac4..061133a9fcf 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -72,6 +72,13 @@ extern EnumPropertyItem normal_space_items[];
extern EnumPropertyItem normal_swizzle_items[];
extern EnumPropertyItem bake_save_mode_items[];
+extern EnumPropertyItem views_format_items[];
+extern EnumPropertyItem views_format_multilayer_items[];
+extern EnumPropertyItem views_format_multiview_items[];
+extern EnumPropertyItem stereo3d_display_items[];
+extern EnumPropertyItem stereo3d_anaglyph_type_items[];
+extern EnumPropertyItem stereo3d_interlace_type_items[];
+
extern EnumPropertyItem exr_codec_items[];
extern EnumPropertyItem color_sets_items[];
@@ -125,6 +132,7 @@ extern EnumPropertyItem object_axis_unsigned_items[];
extern EnumPropertyItem controller_type_items[];
extern EnumPropertyItem render_pass_type_items[];
+extern EnumPropertyItem render_pass_debug_type_items[];
extern EnumPropertyItem keymap_propvalue_items[];
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index a9c0f591858..0c99769a390 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -37,10 +37,8 @@ extern "C" {
struct ParameterList;
struct FunctionRNA;
struct PropertyRNA;
-struct EnumPropertyRNA;
struct StructRNA;
struct BlenderRNA;
-struct IDProperty;
struct bContext;
struct Main;
struct ReportList;
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index e366c9bbe2b..f8eb2e1807c 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -47,6 +47,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../bmesh',
+ '../depsgraph',
'../editors/include',
'../gpu',
'../ikplugin',
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index fa7fd6da8bb..e878e0877d2 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -45,6 +45,7 @@ set(DEFSRC
rna_context.c
rna_controller.c
rna_curve.c
+ rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
rna_fluidsim.c
@@ -67,6 +68,7 @@ set(DEFSRC
rna_object.c
rna_object_force.c
rna_packedfile.c
+ rna_palette.c
rna_particle.c
rna_pose.c
rna_property.c
@@ -306,6 +308,7 @@ blender_include_dirs(
../../blenlib
../../bmesh
../../blenfont
+ ../../depsgraph
../../gpu
../../imbuf
../../ikplugin
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 3d190fc6a13..afa4ab3a67d 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -66,6 +66,7 @@ incs = [
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../depsgraph',
'../../editors/include',
'../../gpu',
'../../ikplugin',
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index e0075414615..dfd0f13ec1a 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -936,7 +936,7 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
if (dp->dnaarraylength == 1) {
if (prop->type == PROP_BOOLEAN && dp->booleanbit) {
- fprintf(f, " if (%svalues[i]) data->%s |= (%d<<i);\n",
+ fprintf(f, " if (%svalues[i]) data->%s |= (%du << i);\n",
(dp->booleannegative) ? "!" : "", dp->dnaname, dp->booleanbit);
fprintf(f, " else data->%s &= ~(%du << i);\n", dp->dnaname, dp->booleanbit);
}
@@ -2027,7 +2027,8 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
if ((func->flag & FUNC_NO_SELF) == 0) {
WRITE_COMMA;
- if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
else fprintf(f, "(::%s *) this->ptr.data", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2222,7 +2223,8 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
}
if ((func->flag & FUNC_NO_SELF) == 0) {
- if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
else fprintf(f, "\tstruct %s *_self;\n", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2274,7 +2276,8 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
}
if ((func->flag & FUNC_NO_SELF) == 0) {
- if (dsrna->dnaname) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnaname);
else fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2675,7 +2678,8 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
if ((func->flag & FUNC_NO_SELF) == 0) {
if (!first) fprintf(f, ", ");
- if (dsrna->dnaname) fprintf(f, "struct %s *_self", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "struct %s *_self", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "struct %s *_self", dsrna->dnaname);
else fprintf(f, "struct %s *_self", srna->identifier);
first = 0;
}
@@ -3289,6 +3293,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_context.c", NULL, RNA_def_context},
{"rna_controller.c", "rna_controller_api.c", RNA_def_controller},
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
+ {"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_fluidsim.c", NULL, RNA_def_fluidsim},
@@ -3309,6 +3314,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_object.c", "rna_object_api.c", RNA_def_object},
{"rna_object_force.c", NULL, RNA_def_object_force},
{"rna_packedfile.c", NULL, RNA_def_packedfile},
+ {"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_property.c", NULL, RNA_def_gameproperty},
@@ -3762,7 +3768,7 @@ static const char *cpp_classes = ""
"\n"
"class DefaultCollectionFunctions {\n"
"public:\n"
-" DefaultCollectionFunctions(const PointerRNA &p) {}\n"
+" DefaultCollectionFunctions(const PointerRNA & /*p*/) {}\n"
"};\n"
"\n"
"\n";
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 009e3799c49..b87b455b36f 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
+#include "BKE_icons.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -406,6 +408,183 @@ static void rna_Library_filepath_set(PointerRNA *ptr, const char *value)
BKE_library_filepath_set(lib, value);
}
+/* ***** ImagePreview ***** */
+
+static void rna_ImagePreview_is_custom_set(PointerRNA *ptr, int value, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ if ((value && (prv_img->flag[size] & PRV_USER_EDITED)) || (!value && !(prv_img->flag[size] & PRV_USER_EDITED))) {
+ return;
+ }
+
+ if (value)
+ prv_img->flag[size] |= PRV_USER_EDITED;
+ else
+ prv_img->flag[size] &= ~PRV_USER_EDITED;
+
+ prv_img->flag[size] |= PRV_CHANGED;
+
+ BKE_previewimg_clear_single(prv_img, size);
+}
+
+static void rna_ImagePreview_size_get(PointerRNA *ptr, int *values, enum eIconSizes size)
+{
+ ID *id = (ID *)ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ values[0] = prv_img->w[size];
+ values[1] = prv_img->h[size];
+}
+
+static void rna_ImagePreview_size_set(PointerRNA *ptr, const int *values, enum eIconSizes size)
+{
+ ID *id = (ID *)ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ if (values[0] && values[1]) {
+ prv_img->rect[size] = MEM_callocN(values[0] * values[1] * sizeof(unsigned int), "prv_rect");
+ }
+
+ prv_img->w[size] = values[0];
+ prv_img->h[size] = values[1];
+
+ prv_img->flag[size] |= (PRV_CHANGED | PRV_USER_EDITED);
+}
+
+static int rna_ImagePreview_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION], enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ length[0] = prv_img->w[size] * prv_img->h[size];
+
+ return length[0];
+}
+
+static void rna_ImagePreview_pixels_get(PointerRNA *ptr, int *values, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ memcpy(values, prv_img->rect[size], prv_img->w[size] * prv_img->h[size] * sizeof(unsigned int));
+}
+
+static void rna_ImagePreview_pixels_set(PointerRNA *ptr, const int *values, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ memcpy(prv_img->rect[size], values, prv_img->w[size] * prv_img->h[size] * sizeof(unsigned int));
+ prv_img->flag[size] |= PRV_USER_EDITED;
+}
+
+static void rna_ImagePreview_is_image_custom_set(PointerRNA *ptr, int value)
+{
+ rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_size_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_size_get(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_size_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_size_set(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static int rna_ImagePreview_image_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_pixels_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_pixels_get(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_pixels_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_is_icon_custom_set(PointerRNA *ptr, int value)
+{
+ rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_size_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_size_get(ptr, values, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_size_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_size_set(ptr, values, ICON_SIZE_ICON);
+}
+
+static int rna_ImagePreview_icon_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_pixels_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_pixels_get(ptr, values, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_pixels_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_ICON);
+}
+
+static int rna_ImagePreview_icon_id_get(PointerRNA *ptr)
+{
+ /* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */
+ return BKE_icon_preview_ensure((PreviewImage *)(ptr->data));
+}
+static void rna_ImagePreview_icon_reload(PreviewImage *prv)
+{
+ /* will lazy load on next use, but only in case icon is not user-modified! */
+ if (!(prv->flag[ICON_SIZE_ICON] & PRV_USER_EDITED) && !(prv->flag[ICON_SIZE_PREVIEW] & PRV_USER_EDITED)) {
+ BKE_previewimg_clear(prv);
+ }
+}
+
#else
static void rna_def_ID_properties(BlenderRNA *brna)
@@ -524,6 +703,62 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
}
+static void rna_def_image_preview(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ImagePreview", NULL);
+ RNA_def_struct_sdna(srna, "PreviewImage");
+ RNA_def_struct_ui_text(srna, "Image Preview", "Preview image and icon");
+
+ prop = RNA_def_property(srna, "is_image_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag[ICON_SIZE_PREVIEW]", PRV_USER_EDITED);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_ImagePreview_is_image_custom_set");
+ RNA_def_property_ui_text(prop, "Custom Image", "True if this preview image has been modified by py script,"
+ "and is no more auto-generated by Blender");
+
+ prop = RNA_def_int_vector(srna, "image_size", 2, NULL, 0, 0, "Image Size",
+ "Width and height in pixels", 0, 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_image_size_get", "rna_ImagePreview_image_size_set", NULL);
+
+ prop = RNA_def_property(srna, "image_pixels", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_multi_array(prop, 1, NULL);
+ RNA_def_property_ui_text(prop, "Image Pixels", "Image pixels, as bytes (always RGBA 32bits)");
+ RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_image_pixels_get_length");
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_image_pixels_get", "rna_ImagePreview_image_pixels_set", NULL);
+
+
+ prop = RNA_def_property(srna, "is_icon_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag[ICON_SIZE_ICON]", PRV_USER_EDITED);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_ImagePreview_is_icon_custom_set");
+ RNA_def_property_ui_text(prop, "Custom Icon", "True if this preview icon has been modified by py script,"
+ "and is no more auto-generated by Blender");
+
+ prop = RNA_def_int_vector(srna, "icon_size", 2, NULL, 0, 0, "Icon Size",
+ "Width and height in pixels", 0, 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_size_get", "rna_ImagePreview_icon_size_set", NULL);
+
+ prop = RNA_def_property(srna, "icon_pixels", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_multi_array(prop, 1, NULL);
+ RNA_def_property_ui_text(prop, "Icon Pixels", "Icon pixels, as bytes (always RGBA 32bits)");
+ RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_icon_pixels_get_length");
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_pixels_get", "rna_ImagePreview_icon_pixels_set", NULL);
+
+ prop = RNA_def_int(srna, "icon_id", 0, INT_MIN, INT_MAX, "Icon ID",
+ "Unique integer identifying this preview as an icon (zero means invalid)", INT_MIN, INT_MAX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_id_get", NULL, NULL);
+
+ func = RNA_def_function(srna, "reload", "rna_ImagePreview_icon_reload");
+ RNA_def_function_ui_description(func, "Reload the preview from its source path");
+}
+
static void rna_def_ID(BlenderRNA *brna)
{
StructRNA *srna;
@@ -566,7 +801,9 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_DOIT);
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
- RNA_def_property_ui_text(prop, "Tag", "Tools can use this to tag data (initial state is undefined)");
+ RNA_def_property_ui_text(prop, "Tag",
+ "Tools can use this to tag data for their own purposes "
+ "(initial state is undefined)");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_ID_RECALC);
@@ -598,17 +835,19 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Clear the user count of a datablock so its not saved, "
"on reload the data will be removed");
- func = RNA_def_function(srna, "animation_data_create", "BKE_id_add_animdata");
+ func = RNA_def_function(srna, "animation_data_create", "BKE_animdata_add_id");
RNA_def_function_ui_description(func, "Create animation data to this ID, note that not all ID types support this");
parm = RNA_def_pointer(func, "anim_data", "AnimData", "", "New animation data or NULL");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "animation_data_clear", "BKE_free_animdata");
+ func = RNA_def_function(srna, "animation_data_clear", "BKE_animdata_free");
RNA_def_function_ui_description(func, "Clear animation on this this ID");
func = RNA_def_function(srna, "update_tag", "rna_ID_update_tag");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Tag the ID to update its display data");
+ RNA_def_function_ui_description(func,
+ "Tag the ID to update its display data, "
+ "e.g. when calling :class:`bpy.types.Scene.update`");
RNA_def_enum_flag(func, "refresh", update_flag_items, 0, "", "Type of updates to perform");
}
@@ -647,6 +886,7 @@ void RNA_def_ID(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Any Type", "RNA type used for pointers to any possible data");
rna_def_ID(brna);
+ rna_def_image_preview(brna);
rna_def_ID_properties(brna);
rna_def_ID_materials(brna);
rna_def_library(brna);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 2a0fd14e13b..ef798820321 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1622,7 +1622,7 @@ bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
{
int len = 1, index;
- bool driven;
+ bool driven, special;
if (!prop)
return false;
@@ -1631,7 +1631,7 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
len = RNA_property_array_length(ptr, prop);
for (index = 0; index < len; index++) {
- if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven))
+ if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven, &special))
return true;
}
@@ -6517,6 +6517,12 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
/* In case of IDProperty, we have to find the *real* idprop of ptr,
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
+
+ /* its possible the custom-prop doesn't exist on this datablock */
+ if (prop == NULL) {
+ return false;
+ }
+
/* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
if (prop == fromprop) {
fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 3fed505b9d6..29e699a57b2 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -329,6 +329,21 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "filter_fcurve_name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "searchstr");
RNA_def_property_ui_text(prop, "F-Curve Name Filter", "F-Curve live filtering string");
+ RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ /* NLA Name Search Settings (Shared with FCurve setting, but with different labels) */
+ prop = RNA_def_property(srna, "use_filter_text", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_BY_FCU_NAME);
+ RNA_def_property_ui_text(prop, "Only Matching Channels",
+ "Only include channels with names containing search text");
+ RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "searchstr");
+ RNA_def_property_ui_text(prop, "Name Filter", "Live filtering string");
+ RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* NLA Specific Settings */
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index df1e6dd55dd..ac30c615438 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -112,6 +112,7 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
adt = BKE_animdata_from_id(ownerId);
if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(ownerId, OB_RECALC_TIME);
}
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 421d7b28dda..93e5ceaa229 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -247,8 +247,8 @@ static void rna_bone_layer_set(int *layer, const int *values)
return;
for (i = 0; i < 32; i++) {
- if (values[i]) *layer |= (1 << i);
- else *layer &= ~(1 << i);
+ if (values[i]) *layer |= (1u << i);
+ else *layer &= ~(1u << i);
}
}
@@ -272,8 +272,8 @@ static void rna_Armature_layer_set(PointerRNA *ptr, const int *values)
return;
for (i = 0; i < 32; i++) {
- if (values[i]) arm->layer |= (1 << i);
- else arm->layer &= ~(1 << i);
+ if (values[i]) arm->layer |= (1u << i);
+ else arm->layer &= ~(1u << i);
}
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 81ba3a9066f..b03b099048f 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -111,8 +111,6 @@ EnumPropertyItem brush_image_tool_items[] = {
#include "MEM_guardedalloc.h"
-#include "DNA_object_types.h"
-
#include "RNA_access.h"
#include "BKE_texture.h"
@@ -125,9 +123,7 @@ EnumPropertyItem brush_image_tool_items[] = {
static int rna_SculptToolCapabilities_has_accumulate_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool,
- SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER);
+ return SCULPT_TOOL_HAS_ACCUMULATE(br->sculpt_tool);
}
static int rna_SculptToolCapabilities_has_auto_smooth_get(PointerRNA *ptr)
@@ -155,7 +151,7 @@ static int rna_SculptToolCapabilities_has_jitter_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK);
+ return SCULPT_TOOL_HAS_NORMAL_WEIGHT(br->sculpt_tool);
}
static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
@@ -344,8 +340,8 @@ static void rna_Brush_reset_icon(Brush *br, const char *UNUSED(type))
return;
if (id->icon_id >= BIFICONID_LAST) {
- BKE_icon_delete(id);
- BKE_previewimg_free_id(id);
+ BKE_icon_id_delete(id);
+ BKE_previewimg_id_free(id);
}
id->icon_id = 0;
@@ -417,8 +413,8 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
br->id.icon_id = 0;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_previewimg_get(&br->id);
- BKE_icon_changed(BKE_icon_getid(&br->id));
+ BKE_previewimg_id_ensure(&br->id);
+ BKE_icon_changed(BKE_icon_id_ensure(&br->id));
}
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 31e991dd2b6..16f74a05f7b 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -87,8 +87,74 @@ static void rna_Camera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointer
DAG_id_tag_update(&camera->id, 0);
}
+static void rna_Camera_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Camera *camera = (Camera *)ptr->id.data;
+ DAG_relations_tag_update(bmain);
+ DAG_id_tag_update(&camera->id, 0);
+}
+
#else
+static void rna_def_camera_stereo_data(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem convergence_mode_items[] = {
+ {CAM_S3D_OFFAXIS, "OFFAXIS", 0, "Off-Axis", "Off-axis frustums converging in a plane"},
+ {CAM_S3D_PARALLEL, "PARALLEL", 0, "Parallel", "Parallel cameras with no convergence"},
+ {CAM_S3D_TOE, "TOE", 0, "Toe-in", "Rotated cameras, looking at the convergence distance"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem pivot_items[] = {
+ {CAM_S3D_PIVOT_LEFT, "LEFT", 0, "Left", ""},
+ {CAM_S3D_PIVOT_RIGHT, "RIGHT", 0, "Right", ""},
+ {CAM_S3D_PIVOT_CENTER, "CENTER", 0, "Center", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CameraStereoData", NULL);
+ RNA_def_struct_sdna(srna, "CameraStereoSettings");
+ RNA_def_struct_nested(brna, srna, "Camera");
+ RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera datablock");
+
+ prop = RNA_def_property(srna, "convergence_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, convergence_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pivot", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, pivot_items);
+ RNA_def_property_ui_text(prop, "Pivot", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Interocular Distance",
+ "Set the distance between the eyes - the stereo plane distance / 30 should be fine");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "convergence_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 15.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Convergence Plane Distance",
+ "The converge point for the stereo cameras "
+ "(often the distance between a projector and the projection screen)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "viewport_convergence", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "convergence_distance");
+ RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 15.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Viewport Convergence",
+ "Preview convergence distance for the stereo effect in the viewport "
+ "(it does not affect the render!)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+}
+
void RNA_def_camera(BlenderRNA *brna)
{
StructRNA *srna;
@@ -241,6 +307,13 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "DOF Distance", "Distance to the focus point for depth of field");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ /* Stereo Settings */
+ prop = RNA_def_property(srna, "stereo", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo");
+ RNA_def_property_struct_type(prop, "CameraStereoData");
+ RNA_def_property_ui_text(prop, "Stereo", "");
+
/* flag */
prop = RNA_def_property(srna, "show_limits", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWLIMITS);
@@ -265,7 +338,8 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_safe_center", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_SAFE_CENTER);
- RNA_def_property_ui_text(prop, "Show Center-cut safe areas", "Show safe areas to fit content in a different aspect ratio");
+ RNA_def_property_ui_text(prop, "Show Center-cut safe areas",
+ "Show safe areas to fit content in a different aspect ratio");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "show_name", PROP_BOOLEAN, PROP_NONE);
@@ -289,7 +363,7 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "dof_ob");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "DOF Object", "Use this object to define the depth of field focal point");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
prop = RNA_def_property(srna, "gpu_dof", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPUDOFSettings");
@@ -298,6 +372,12 @@ void RNA_def_camera(BlenderRNA *brna)
rna_def_animdata_common(srna);
+ /* Nested Data */
+ RNA_define_animate_sdna(true);
+
+ /* *** Animated *** */
+ rna_def_camera_stereo_data(brna);
+
/* Camera API */
RNA_api_camera(srna);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5e114a51ceb..8ea67a34fbb 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -447,6 +447,7 @@ static void rna_ColorManagedDisplaySettings_display_device_update(Main *UNUSED(b
IMB_colormanagement_validate_settings(&scene->display_settings, &scene->view_settings);
+ DAG_id_tag_update(id, 0);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
}
@@ -619,10 +620,8 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
}
if (seq_found) {
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
+
if (seq->strip->proxy && seq->strip->proxy->anim) {
IMB_free_anim(seq->strip->proxy->anim);
seq->strip->proxy->anim = NULL;
@@ -634,10 +633,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
else {
SEQ_BEGIN(scene->ed, seq);
{
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
}
SEQ_END;
@@ -677,7 +673,7 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
static float rna_CurveMap_evaluateF(struct CurveMap *cuma, ReportList *reports, float value)
{
if (!cuma->table) {
- BKE_reportf(reports, RPT_ERROR, "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap");
+ BKE_report(reports, RPT_ERROR, "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap");
return 0.0f;
}
return curvemap_evaluateF(cuma, value);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index aaacf07567e..abc489bb9b0 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -241,7 +241,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "constraints", oldname, con->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "constraints", oldname, con->name);
}
static char *rna_Constraint_path(PointerRNA *ptr)
@@ -271,12 +271,12 @@ static char *rna_Constraint_path(PointerRNA *ptr)
static void rna_Constraint_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- ED_object_constraint_update(ptr->id.data);
+ ED_object_constraint_tag_update(ptr->id.data, ptr->data);
}
static void rna_Constraint_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- ED_object_constraint_dependency_update(bmain, ptr->id.data);
+ ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, ptr->data);
}
static void rna_Constraint_influence_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -323,7 +323,7 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1357,7 +1357,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "orglength");
- RNA_def_property_range(prop, 0.0, 100.f);
+ RNA_def_property_range(prop, 0.0, 1000.f);
+ RNA_def_property_ui_range(prop, 0, 100.0f, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Original Length", "Length at rest position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index ba0214d36ec..605e28653f9 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -120,7 +120,7 @@ static int rna_Controller_state_number_get(struct PointerRNA *ptr)
int bit;
for (bit = 0; bit < 32; bit++) {
- if (cont->state_mask & (1 << bit))
+ if (cont->state_mask & (1u << bit))
return bit + 1;
}
return 0;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 29f1dd5f29f..fc028a46b78 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -46,9 +46,6 @@
#include "WM_types.h"
-#include "BKE_curve.h"
-#include "ED_curve.h"
-
#ifndef RNA_RUNTIME
static EnumPropertyItem beztriple_handle_type_items[] = {
{HD_FREE, "FREE", 0, "Free", ""},
@@ -124,8 +121,6 @@ static const EnumPropertyItem curve2d_fill_mode_items[] = {
#ifdef RNA_RUNTIME
-#include "BLI_math.h"
-
#include "DNA_object_types.h"
#include "BKE_curve.h"
@@ -1300,16 +1295,13 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
func = RNA_def_function(srna, "clear", "rna_Curve_spline_clear");
- RNA_def_function_ui_description(func, "Remove all spline from a curve");
+ RNA_def_function_ui_description(func, "Remove all splines from a curve");
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_struct_type(prop, "Spline");
RNA_def_property_pointer_funcs(prop, "rna_Curve_active_spline_get", "rna_Curve_active_spline_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Spline", "Active curve spline");
- /* Could call: ED_base_object_activate(C, scene->basact);
- * but would be a bad level call and it seems the notifier is enough */
- RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 6a0ae0a60f8..a239bf3ae4c 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -533,7 +533,7 @@ BlenderRNA *RNA_create(void)
brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA");
DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
- DefRNA.structs.first = DefRNA.structs.last = NULL;
+ BLI_listbase_clear(&DefRNA.structs);
DefRNA.error = 0;
DefRNA.preprocess = 1;
@@ -720,8 +720,8 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
* use MEM_dupallocN, data structs may not be alloced but builtin */
memcpy(srna, srnafrom, sizeof(StructRNA));
srna->cont.prophash = NULL;
- srna->cont.properties.first = srna->cont.properties.last = NULL;
- srna->functions.first = srna->functions.last = NULL;
+ BLI_listbase_clear(&srna->cont.properties);
+ BLI_listbase_clear(&srna->functions);
srna->py_type = NULL;
if (DefRNA.preprocess) {
@@ -3411,7 +3411,7 @@ static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop)
if (prop->flag & PROP_RUNTIME) {
if (cont->prophash)
- BLI_ghash_remove(cont->prophash, (void *)prop->identifier, NULL, NULL);
+ BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL);
RNA_def_property_free_pointers(prop);
rna_freelinkN(&cont->properties, prop);
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
new file mode 100644
index 00000000000..8ac1e2acc60
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -0,0 +1,112 @@
+/*
+ * ***** 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): Blender Foundation (2014).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_depsgraph.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_depsgraph.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_report.h"
+
+#include "DEG_depsgraph_debug.h"
+
+static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
+{
+ FILE *f = fopen(filename, "w");
+ if (f == NULL)
+ return;
+
+ DEG_debug_graphviz(graph, f, "Depsgraph", false);
+
+ fclose(f);
+}
+
+static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
+{
+ Scene *sce;
+ DAG_relations_tag_update(bmain);
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ DAG_scene_relations_rebuild(bmain, sce);
+ DEG_graph_on_visible_update(bmain, sce);
+ }
+}
+
+static void rna_Depsgraph_debug_stats(Depsgraph *graph, ReportList *reports)
+{
+ size_t outer, ops, rels;
+
+ DEG_stats_simple(graph, &outer, &ops, &rels);
+
+ // XXX: report doesn't seem to work
+ printf("Approx %lu Operations, %lu Relations, %lu Outer Nodes\n",
+ ops, rels, outer);
+
+ BKE_reportf(reports, RPT_WARNING, "Approx. %lu Operations, %lu Relations, %lu Outer Nodes",
+ ops, rels, outer);
+}
+
+#else
+
+static void rna_def_depsgraph(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "Depsgraph", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph", "");
+
+ 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);
+
+ 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);
+}
+
+void RNA_def_depsgraph(BlenderRNA *brna)
+{
+ rna_def_depsgraph(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 6c893255601..576af7b3a1c 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -574,7 +574,7 @@ static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max
static void rna_FModifier_verify_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)ptr->data;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 6b61b37ce5c..7d7df0f91a7 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -568,7 +568,7 @@ static void rna_def_gpencil_frame(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_number", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "framenum");
/* XXX note: this cannot occur on the same frame as another sketch */
- RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Frame Number", "The frame on which this sketch appears");
/* Flags */
@@ -579,7 +579,9 @@ static void rna_def_gpencil_frame(BlenderRNA *brna)
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_FRAME_SELECT);
RNA_def_property_ui_text(prop, "Select", "Frame is selected for editing in the Dope Sheet");
-
+
+
+ /* API */
func = RNA_def_function(srna, "clear", "rna_GPencil_frame_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil frame data");
}
@@ -773,8 +775,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG);
RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)");
- RNA_def_property_update_runtime(prop, "rna_GPencil_update");
-
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* X-Ray */
prop = RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_NO_XRAY);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index cf2973c49a7..8b464e74569 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -35,6 +35,7 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
+#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -137,6 +138,23 @@ static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scen
WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
}
+static void rna_Image_views_format_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ Image *ima = ptr->id.data;
+ ImBuf *ibuf;
+ void *lock;
+
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ ImageUser iuser = {NULL};
+ iuser.scene = scene;
+ BKE_image_signal(ima, &iuser, IMA_SIGNAL_FREE);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
static void rna_ImageUser_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
ImageUser *iuser = ptr->data;
@@ -295,17 +313,16 @@ static int rna_Image_frame_duration_get(PointerRNA *ptr)
Image *ima = ptr->id.data;
int duration = 1;
- if (!ima->anim) {
+ if (BKE_image_has_anim(ima)) {
+ duration = IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN);
+ }
+ else {
/* acquire ensures ima->anim is set, if possible! */
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
BKE_image_release_ibuf(ima, ibuf, lock);
}
- if (ima->anim) {
- duration = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
- }
-
return duration;
}
@@ -409,6 +426,19 @@ static int rna_Image_is_float_get(PointerRNA *ptr)
return is_float;
}
+static PointerRNA rna_Image_packed_file_get(PointerRNA *ptr)
+{
+ Image *ima = (Image *)ptr->id.data;
+
+ if (BKE_image_has_packedfile(ima)) {
+ ImagePackedFile *imapf = ima->packedfiles.first;
+ return rna_pointer_inherit_refine(ptr, &RNA_PackedFile, imapf->packedfile);
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
static void rna_Image_render_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Image *image = (Image *)ptr->id.data;
@@ -508,10 +538,31 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
RNA_def_property_ui_text(prop, "Layer", "Layer in multilayer image");
- prop = RNA_def_property(srna, "multilayer_pass", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "pass");
+ prop = RNA_def_property(srna, "multilayer_view", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
- RNA_def_property_ui_text(prop, "Pass", "Pass in multilayer image");
+ RNA_def_property_ui_text(prop, "View", "View in multilayer image");
+}
+
+/* image.packed_files */
+static void rna_def_image_packed_files(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ImagePackedFile", NULL);
+ RNA_def_struct_sdna(srna, "ImagePackedFile");
+
+ prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
+ RNA_def_property_ui_text(prop, "Packed File", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "filepath");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_render_slot(BlenderRNA *brna)
@@ -613,15 +664,23 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PackedFile");
RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
- RNA_def_property_ui_text(prop, "Packed File", "");
-
+ RNA_def_property_pointer_funcs(prop, "rna_Image_packed_file_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Packed File", "First packed file of the image");
+
+ prop = RNA_def_property(srna, "packed_files", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "packedfiles", NULL);
+ RNA_def_property_struct_type(prop, "ImagePackedFile");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images");
+
prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_field_order_items);
RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
+
/* booleans */
prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
@@ -645,6 +704,21 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
+
+ prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_STEREO);
+ RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_MULTIVIEW);
+ RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -825,6 +899,19 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
+ /* multiview */
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
RNA_api_image(srna);
}
@@ -834,6 +921,7 @@ void RNA_def_image(BlenderRNA *brna)
rna_def_render_slots(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
+ rna_def_image_packed_files(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 357490924f2..c3c152a10b6 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -35,6 +35,7 @@
#include <time.h>
#include "DNA_packedFile_types.h"
+#include "DNA_userdef_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -55,8 +56,8 @@
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
-#include "BIF_gl.h"
#include "GPU_draw.h"
+#include "GPU_debug.h"
#include "DNA_image_types.h"
#include "DNA_scene_types.h"
@@ -115,9 +116,14 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
BLI_strncpy(filename, image->name, sizeof(filename));
BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id));
- if (image->packedfile) {
- if (writePackedFile(reports, image->name, image->packedfile, 0) != RET_OK) {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'", image->id.name + 2, image->name);
+ if (BKE_image_has_packedfile(image)) {
+ ImagePackedFile *imapf;
+
+ for (imapf = image->packedfiles.first; imapf; imapf = imapf->next) {
+ if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
+ BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'",
+ image->id.name + 2, imapf->filepath);
+ }
}
}
else if (IMB_saveiff(ibuf, filename, ibuf->flags)) {
@@ -152,20 +158,17 @@ static void rna_Image_pack(
BKE_report(reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
}
else {
- if (image->packedfile) {
- freePackedFile(image->packedfile);
- image->packedfile = NULL;
- }
+ BKE_image_free_packedfiles(image);
if (as_png) {
BKE_image_memorypack(image);
}
else if (data) {
char *data_dup = MEM_mallocN(sizeof(*data_dup) * (size_t)data_len, __func__);
memcpy(data_dup, data, (size_t)data_len);
- image->packedfile = newPackedFileMemory(data_dup, data_len);
+ BKE_image_packfiles_from_mem(reports, image, data_dup, (size_t)data_len);
}
else {
- image->packedfile = newPackedFile(reports, image->name, ID_BLEND_PATH(bmain, &image->id));
+ BKE_image_packfiles(reports, image, ID_BLEND_PATH(bmain, &image->id));
}
}
@@ -175,7 +178,7 @@ static void rna_Image_pack(
static void rna_Image_unpack(Image *image, ReportList *reports, int method)
{
- if (!image->packedfile) {
+ if (!BKE_image_has_packedfile(image)) {
BKE_report(reports, RPT_ERROR, "Image not packed");
}
else if (BKE_image_is_animated(image)) {
@@ -232,31 +235,23 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+ /* clean glError buffer */
+ while (glGetError() != GL_NO_ERROR) {}
+
if (ibuf == NULL || ibuf->rect == NULL) {
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
BKE_image_release_ibuf(image, ibuf, NULL);
return (int)GL_INVALID_OPERATION;
}
- /* could be made into a function? */
- glGenTextures(1, (GLuint *)bind);
- glBindTexture(GL_TEXTURE_2D, *bind);
-
- if (filter != GL_NEAREST && filter != GL_LINEAR)
- error = (int)gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y,
+ (filter != GL_NEAREST && filter != GL_LINEAR), false, image);
- if (!error) {
- /* clean glError buffer */
- while (glGetError() != GL_NO_ERROR) {}
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, image->tpageflag & IMA_CLAMP_U ? GL_CLAMP : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, image->tpageflag & IMA_CLAMP_V ? GL_CLAMP : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- error = (int)glGetError();
- }
+ error = glGetError();
if (error) {
glDeleteTextures(1, (GLuint *)bind);
@@ -294,6 +289,11 @@ static void rna_Image_filepath_from_user(Image *image, ImageUser *image_user, ch
BKE_image_user_file_path(image_user, image, filepath);
}
+static void rna_Image_buffers_free(Image *image)
+{
+ BKE_image_free_buffers(image);
+}
+
#else
void RNA_api_image(StructRNA *srna)
@@ -380,6 +380,9 @@ void RNA_api_image(StructRNA *srna)
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
RNA_def_function_output(func, parm);
+ func = RNA_def_function(srna, "buffers_free", "rna_Image_buffers_free");
+ RNA_def_function_ui_description(func, "Free the image buffers from memory");
+
/* TODO, pack/unpack, maybe should be generic functions? */
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index f225387baa4..eab14be9085 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -35,16 +35,13 @@
#define RNA_MAGIC ((int)~0)
-struct ColorBand;
struct ID;
struct IDProperty;
struct Main;
struct Mesh;
struct Object;
-struct RenderEngine;
struct ReportList;
struct SDNA;
-struct Sequence;
/* Data structures used during define */
@@ -143,6 +140,7 @@ void RNA_def_constraint(struct BlenderRNA *brna);
void RNA_def_context(struct BlenderRNA *brna);
void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
+void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
@@ -164,6 +162,7 @@ void RNA_def_nodetree(struct BlenderRNA *brna);
void RNA_def_object(struct BlenderRNA *brna);
void RNA_def_object_force(struct BlenderRNA *brna);
void RNA_def_packedfile(struct BlenderRNA *brna);
+void RNA_def_palette(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 845d76debd2..ba0705b5caa 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -38,10 +38,8 @@ struct StructRNA;
struct PropertyRNA;
struct PointerRNA;
struct FunctionRNA;
-struct ReportList;
struct CollectionPropertyIterator;
struct bContext;
-struct EnumProperty;
struct IDProperty;
struct GHash;
struct Main;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 8a3626de81d..04cba835ae2 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -48,7 +48,6 @@
#include <stddef.h>
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_animsys.h"
#include "BKE_depsgraph.h"
@@ -89,7 +88,7 @@ static void rna_ShapeKey_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "key_blocks", oldname, kb->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "key_blocks", oldname, kb->name);
}
static float rna_ShapeKey_frame_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index c915acdeeac..6140a34b271 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -825,6 +825,12 @@ static void rna_def_sun_lamp(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.001, 100.0, 2, 1);
RNA_def_property_ui_text(prop, "Frustum Size", "Size of the frustum used for creating the shadow map");
RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+
+ prop = RNA_def_property(srna, "show_shadow_box", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_SHADOW_BOX);
+ RNA_def_property_ui_text(prop, "Show Shadow Box",
+ "Draw a box in 3D view to visualize which objects are contained in it");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
}
static void rna_def_hemi_lamp(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index ed8b85f724e..8b5ed66e217 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -35,6 +35,7 @@
#include "DNA_ID.h"
#include "DNA_modifier_types.h"
+#include "DNA_space_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -58,9 +59,11 @@
#include "BKE_library.h"
#include "BKE_object.h"
#include "BKE_material.h"
+#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_text.h"
#include "BKE_action.h"
#include "BKE_group.h"
@@ -87,6 +90,7 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_speaker_types.h"
+#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_texture_types.h"
#include "DNA_group_types.h"
@@ -341,10 +345,10 @@ static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *
}
}
-static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer)
+static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
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);
+ Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
id_us_min(&image->id);
return image;
}
@@ -461,8 +465,8 @@ static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
- Tex *tex = add_texture(bmain, name);
- tex_set_type(tex, type);
+ Tex *tex = BKE_texture_add(bmain, name);
+ BKE_texture_type_set(tex, type);
id_us_min(&tex->id);
return tex;
}
@@ -548,6 +552,25 @@ static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRN
}
}
+static bSound *rna_Main_sounds_load(Main *bmain, const char *name)
+{
+ bSound *sound = BKE_sound_new_file(bmain, name);
+ id_us_min(&sound->id);
+ return sound;
+}
+static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr)
+{
+ Speaker *sound = sound_ptr->data;
+ if (ID_REAL_USERS(sound) <= 0) {
+ BKE_libblock_free(bmain, sound);
+ RNA_POINTER_INVALIDATE(sound_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d",
+ sound->id.name + 2, ID_REAL_USERS(sound));
+ }
+}
+
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
return BKE_text_add(bmain, name);
@@ -705,7 +728,7 @@ static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, Poin
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle = BKE_linestyle_new(name, bmain);
+ FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
id_us_min(&linestyle->id);
return linestyle;
}
@@ -786,11 +809,12 @@ static int rna_Main_linestyle_is_updated_get(PointerRNA *ptr) { return DAG_id_ty
#else
-void RNA_api_main(StructRNA *srna)
+void RNA_api_main(StructRNA *UNUSED(srna))
{
#if 0
FunctionRNA *func;
PropertyRNA *parm;
+
/* maybe we want to add functions in 'bpy.data' still?
* for now they are all in collections bpy.data.images.new(...) */
func = RNA_def_function(srna, "add_image", "rna_Main_add_image");
@@ -799,8 +823,6 @@ void RNA_api_main(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "image", "Image", "", "New image");
RNA_def_function_return(func, parm);
-#else
- (void)srna;
#endif
}
@@ -1174,6 +1196,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_flag(parm, PROP_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");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image datablock");
RNA_def_function_return(func, parm);
@@ -1584,7 +1607,21 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Sounds", "Collection of sounds");
- /* TODO, 'load' */
+ /* load func */
+ 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 datablock");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "sound", "Sound", "", "New text datablock");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
+ parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index afd149a755a..b660236ea4f 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -52,12 +52,10 @@
#ifdef RNA_RUNTIME
-#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "BKE_depsgraph.h"
#include "BKE_mask.h"
-#include "BKE_tracking.h"
#include "BLI_math.h"
@@ -213,10 +211,13 @@ static void rna_MaskLayer_name_set(PointerRNA *ptr, const char *value)
{
Mask *mask = (Mask *)ptr->id.data;
MaskLayer *masklay = (MaskLayer *)ptr->data;
+ char oldname[sizeof(masklay->name)], newname[sizeof(masklay->name)];
- BLI_strncpy(masklay->name, value, sizeof(masklay->name));
+ /* need to be on the stack */
+ BLI_strncpy(oldname, masklay->name, sizeof(masklay->name));
+ BLI_strncpy_utf8(newname, value, sizeof(masklay->name));
- BKE_mask_layer_unique_name(mask, masklay);
+ BKE_mask_layer_rename(mask, masklay, oldname, newname);
}
static PointerRNA rna_MaskLayer_active_spline_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 7a06b647ae3..874e861f75f 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -377,7 +377,7 @@ static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED
MTex *rna_mtex_texture_slots_add(ID *self_id, struct bContext *C, ReportList *reports)
{
- MTex *mtex = add_mtex_id(self_id, -1);
+ MTex *mtex = BKE_texture_mtex_add_id(self_id, -1);
if (mtex == NULL) {
BKE_reportf(reports, RPT_ERROR, "Maximum number of textures added %d", MAX_MTEX);
return NULL;
@@ -398,7 +398,7 @@ MTex *rna_mtex_texture_slots_create(ID *self_id, struct bContext *C, ReportList
return NULL;
}
- mtex = add_mtex_id(self_id, index);
+ mtex = BKE_texture_mtex_add_id(self_id, index);
/* for redraw only */
WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index b1f0adb0d98..ec64aa38275 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -55,6 +55,8 @@ EnumPropertyItem mesh_delimit_mode_items[] = {
{BMO_DELIM_NORMAL, "NORMAL", 0, "Normal", "Delimit by face directions"},
{BMO_DELIM_MATERIAL, "MATERIAL", 0, "Material", "Delimit by face material"},
{BMO_DELIM_SEAM, "SEAM", 0, "Seam", "Delimit by edge seams"},
+ {BMO_DELIM_SHARP, "SHARP", 0, "Sharp", "Delimit by sharp edges"},
+ {BMO_DELIM_UV, "UV", 0, "UVs", "Delimit by UV coordinates"},
{0, NULL, 0, NULL, NULL},
};
@@ -73,7 +75,6 @@ EnumPropertyItem mesh_delimit_mode_items[] = {
#include "ED_mesh.h" /* XXX Bad level call */
#include "WM_api.h"
-#include "WM_types.h"
#include "rna_mesh_utils.h"
@@ -1143,6 +1144,37 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* End skin vertices */
+/* Paint mask */
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
+
+static char *rna_MeshPaintMaskLayer_path(PointerRNA *ptr)
+{
+ CustomDataLayer *cdl = ptr->data;
+ char name_esc[sizeof(cdl->name) * 2];
+ BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
+ return BLI_sprintfN("vertex_paint_masks[\"%s\"]", name_esc);
+}
+
+static char *rna_MeshPaintMask_path(PointerRNA *ptr)
+{
+ return rna_VertCustomData_data_path(ptr, "vertex_paint_masks", CD_PAINT_MASK);
+}
+
+static void rna_MeshPaintMaskLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(MFloatProperty), me->totvert, 0, NULL);
+}
+
+static int rna_MeshPaintMaskLayer_data_length(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return me->totvert;
+}
+
+/* End paint mask */
+
static void rna_TexturePoly_image_set(PointerRNA *ptr, PointerRNA value)
{
MTexPoly *tf = (MTexPoly *)ptr->data;
@@ -1783,6 +1815,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
{
/* unused functions made by macros */
(void)rna_Mesh_skin_vertice_index_range;
+ (void)rna_Mesh_vertex_paint_mask_index_range;
(void)rna_Mesh_tessface_uv_texture_active_set;
(void)rna_Mesh_tessface_uv_texture_clone_get;
(void)rna_Mesh_tessface_uv_texture_clone_index_get;
@@ -3172,6 +3205,36 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshPaintMaskLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Paint Mask Layer", "Per-vertex paint mask data");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshPaintMaskLayer_path");
+
+ prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshPaintMaskProperty");
+ RNA_def_property_ui_text(prop, "Data", "");
+
+ RNA_def_property_collection_funcs(prop, "rna_MeshPaintMaskLayer_data_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get",
+ "rna_MeshPaintMaskLayer_data_length", NULL, NULL, NULL);
+
+ srna = RNA_def_struct(brna, "MeshPaintMaskProperty", NULL);
+ RNA_def_struct_sdna(srna, "MFloatProperty");
+ RNA_def_struct_ui_text(srna, "Mesh Paint Mask Property",
+ "Floating point paint mask value");
+ RNA_def_struct_path_func(srna, "rna_MeshPaintMask_path");
+
+ prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "f");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
static void rna_def_mesh(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3376,6 +3439,16 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_skin_vertices(brna, prop);
/* End skin vertices */
+ /* Paint mask */
+ prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_vertex_paint_masks_begin", NULL, NULL, NULL,
+ "rna_Mesh_vertex_paint_masks_length", NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshPaintMaskLayer");
+ RNA_def_property_ui_text(prop, "Vertex Paint Mask", "Vertex paint mask");
+ rna_def_paint_mask(brna, prop);
+ /* End paint mask */
+
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH);
RNA_def_property_ui_text(prop, "Auto Smooth",
@@ -3404,7 +3477,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_double_sided", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_TWOSIDED);
- RNA_def_property_ui_text(prop, "Double Sided", "Render/display the mesh with double or single sided lighting");
+ RNA_def_property_ui_text(prop, "Double Sided", "Display the mesh with double or single sided lighting (OpenGL only)");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "texco_mesh", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index abf29ef82a3..632b07c19ce 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -69,47 +69,6 @@ static void rna_Mesh_create_normals_split(Mesh *mesh)
}
}
-static void rna_Mesh_calc_normals_split(Mesh *mesh)
-{
- float (*r_loopnors)[3];
- float (*polynors)[3];
- short (*clnors)[2] = NULL;
- bool free_polynors = false;
-
- 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);
- }
- else {
- r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
- CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
-
- /* may be NULL */
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
-
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
- polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- polynors, false);
- free_polynors = true;
- }
-
- 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);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
-}
-
static void rna_Mesh_free_normals_split(Mesh *mesh)
{
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
@@ -130,7 +89,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
/* Compute loop normals if needed. */
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- rna_Mesh_calc_normals_split(mesh);
+ BKE_mesh_calc_normals_split(mesh);
}
BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
@@ -211,6 +170,8 @@ static void rna_Mesh_normals_split_custom_set(Mesh *mesh, ReportList *reports, i
}
rna_Mesh_normals_split_custom_do(mesh, loopnors, false);
+
+ DAG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_normals_split_custom_set_from_vertices(
@@ -227,6 +188,8 @@ static void rna_Mesh_normals_split_custom_set_from_vertices(
}
rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
+
+ DAG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
@@ -256,7 +219,7 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "create_normals_split", "rna_Mesh_create_normals_split");
RNA_def_function_ui_description(func, "Empty split vertex normals");
- func = RNA_def_function(srna, "calc_normals_split", "rna_Mesh_calc_normals_split");
+ func = RNA_def_function(srna, "calc_normals_split", "BKE_mesh_calc_normals_split");
RNA_def_function_ui_description(func, "Calculate split vertex normals, which preserve sharp edges");
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 656c19e8108..087db2bedcd 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -92,6 +92,7 @@ EnumPropertyItem modifier_type_items[] = {
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
+ {eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Corrective Smooth", ""},
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
@@ -377,6 +378,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
return &RNA_NormalEditModifier;
+ case eModifierType_CorrectiveSmooth:
+ return &RNA_CorrectiveSmoothModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -405,7 +408,7 @@ static void rna_Modifier_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "modifiers", oldname, md->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "modifiers", oldname, md->name);
}
static char *rna_Modifier_path(PointerRNA *ptr)
@@ -444,6 +447,7 @@ RNA_MOD_VGROUP_NAME_SET(Cast, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Curve, name);
RNA_MOD_VGROUP_NAME_SET(DataTransfer, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Decimate, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(CorrectiveSmooth, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Displace, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Hook, name);
RNA_MOD_VGROUP_NAME_SET(LaplacianDeform, anchor_grp_name);
@@ -1034,6 +1038,33 @@ static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, Po
return item;
}
+static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ rna_Modifier_update(bmain, scene, ptr);
+}
+
+static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ MEM_SAFE_FREE(csmd->bind_coords);
+ csmd->bind_coords_num = 0;
+ }
+
+ rna_CorrectiveSmoothModifier_update(bmain, scene, ptr);
+}
+
+static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+ return (csmd->bind_coords != NULL);
+}
+
#else
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
@@ -1402,7 +1433,7 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "tolerance");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1, 0.01, 6);
- RNA_def_property_ui_text(prop, "Merge Limit", "Distance from axis within which mirrored vertices are merged");
+ RNA_def_property_ui_text(prop, "Merge Limit", "Distance within which mirrored vertices are merged");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "mirror_object", PROP_POINTER, PROP_NONE);
@@ -1475,6 +1506,13 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_TRIANGULATE);
RNA_def_property_ui_text(prop, "Triangulate", "Keep triangulated faces resulting from decimation (collapse only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "defgrp_factor");
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 4);
+ RNA_def_property_ui_text(prop, "Factor", "Vertex group strength");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* end collapse-only option */
/* (mode == MOD_DECIM_MODE_DISSOLVE) */
@@ -2111,6 +2149,90 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+
+static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem modifier_smooth_type_items[] = {
+ {MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE, "SIMPLE", 0, "Simple",
+ "Use the average of adjacent edge-vertices"},
+ {MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT, "LENGTH_WEIGHTED", 0, "Length Weight",
+ "Use the average of adjacent edge-vertices weighted by their length"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem modifier_rest_source_items[] = {
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO, "ORCO", 0, "Original Coords",
+ "Use base mesh vert coords as the rest position"},
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND, "BIND", 0, "Bind Coords",
+ "Use bind vert coords for rest position"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CorrectiveSmoothModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Corrective Smooth Modifier", "Correct distortion caused by deformation");
+ RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "lambda");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 5, 3);
+ RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "repeat");
+ RNA_def_property_ui_range(prop, 0, 200, 1, -1);
+ RNA_def_property_ui_text(prop, "Repeat", "");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "rest_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rest_source");
+ RNA_def_property_enum_items(prop, modifier_rest_source_items);
+ RNA_def_property_ui_text(prop, "Rest Source", "Select the source of rest positions");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_rest_source_update");
+
+ prop = RNA_def_property(srna, "smooth_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "smooth_type");
+ RNA_def_property_enum_items(prop, modifier_smooth_type_items);
+ RNA_def_property_ui_text(prop, "Smooth Type", "Method used for smoothing");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(prop, "Vertex Group",
+ "Name of Vertex Group which determines influence of modifier per point");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CorrectiveSmoothModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "is_bind", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Bind current shape", "");
+ RNA_def_property_boolean_funcs(prop, "rna_CorrectiveSmoothModifier_is_bind_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_only_smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_ONLY_SMOOTH);
+ RNA_def_property_ui_text(prop, "Only Smooth",
+ "Apply smoothing without reconstructing the surface");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_pin_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_PIN_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Pin Boundaries",
+ "Excludes boundary vertices from being smoothed");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+}
+
+
static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4185,7 +4307,7 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_boolean(srna, "use_object_transform", true, "Object Transform",
- "Evaluate source and destination meshes in their respective object spaces");
+ "Evaluate source and destination meshes in global space");
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_OBSRC_TRANSFORM);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4418,7 +4540,7 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NormalEditModifier_defgrp_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_NORMALEDIT_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4520,6 +4642,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_displace(brna);
rna_def_modifier_uvproject(brna);
rna_def_modifier_smooth(brna);
+ rna_def_modifier_correctivesmooth(brna);
rna_def_modifier_cast(brna);
rna_def_modifier_meshdeform(brna);
rna_def_modifier_particlesystem(brna);
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index e891ab520f9..9ccde654af2 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -196,7 +196,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, clip_tc_items);
RNA_def_property_ui_text(prop, "Timecode", "");
- RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update");
/* directory */
prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index eb2cb9e9312..4df954b062b 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -30,7 +30,6 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -39,7 +38,6 @@
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "DNA_text_types.h"
#include "DNA_texture_types.h"
@@ -48,7 +46,6 @@
#include "BKE_node.h"
#include "BKE_image.h"
#include "BKE_texture.h"
-#include "BKE_idprop.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -1549,7 +1546,7 @@ static void rna_Node_name_set(PointerRNA *ptr, const char *value)
nodeUniqueName(ntree, node);
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "nodes", oldname, node->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "nodes", oldname, node->name);
}
static bNodeSocket *rna_Node_inputs_new(ID *id, bNode *node, ReportList *reports, const char *type, const char *name, const char *identifier)
@@ -1578,7 +1575,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id, bNode *node, ReportList *report
sock = nodeAddSocket(ntree, node, SOCK_OUT, type, identifier, name);
if (sock == NULL) {
- BKE_reportf(reports, RPT_ERROR, "Unable to create socket");
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
ntreeUpdateTree(G.main, ntree);
@@ -2258,8 +2255,13 @@ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *
nodeFindNode(ntree, sock, &node, NULL);
}
- if (node)
+ if (node) {
nodeSynchronizeID(node, true);
+
+ /* extra update for sockets that get synced to material */
+ if (node->id && ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT))
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, node->id);
+ }
}
@@ -2616,6 +2618,70 @@ static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), Pointer
return item;
}
+static int rna_Node_image_has_layers_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+
+ if (!ima || !(ima->rr)) return 0;
+
+ return RE_layers_have_name(ima->rr);
+}
+
+static int rna_Node_image_has_views_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+
+ if (!ima || !(ima->rr)) return 0;
+
+ return BLI_listbase_count_ex(&ima->rr->views, 2) > 1;
+}
+
+static EnumPropertyItem *renderresult_views_add_enum(RenderView *rv)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "ALL", 0, "All", ""};
+ int i = 1, totitem = 0;
+
+ /* option to use all views */
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ while (rv) {
+ tmp.identifier = rv->name;
+ /* little trick: using space char instead empty string makes the item selectable in the dropdown */
+ if (rv->name[0] == '\0')
+ tmp.name = " ";
+ else
+ tmp.name = rv->name;
+ tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ rv = rv->next;
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+
+ return item;
+}
+
+static EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *free)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+ EnumPropertyItem *item = NULL;
+ RenderView *rv;
+
+ if (!ima || !(ima->rr)) return NULL;
+
+ rv = ima->rr->views.first;
+ item = renderresult_views_add_enum(rv);
+
+ *free = true;
+
+ return item;
+}
+
static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2701,7 +2767,7 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNode *node = ptr->data;
- init_tex_mapping(node->storage);
+ BKE_texture_mapping_init(node->storage);
rna_Node_update(bmain, scene, ptr);
}
@@ -2907,6 +2973,11 @@ static EnumPropertyItem prop_image_layer_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem prop_image_view_items[] = {
+ { 0, "ALL", 0, "All", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
static EnumPropertyItem prop_scene_layer_items[] = {
{ 0, "PLACEHOLDER", 0, "Placeholder", ""},
{0, NULL, 0, NULL, NULL}
@@ -3234,6 +3305,8 @@ static void def_sh_mapping(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static float default_1[3] = {1.f, 1.f, 1.f};
+
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
@@ -3257,6 +3330,7 @@ static void def_sh_mapping(StructRNA *srna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
+ RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(prop, "Scale", "");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
@@ -3268,6 +3342,7 @@ static void def_sh_mapping(StructRNA *srna)
prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "max");
+ RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
@@ -3410,6 +3485,7 @@ static void def_sh_tex_environment(StructRNA *srna)
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3475,6 +3551,7 @@ static void def_sh_tex_image(StructRNA *srna)
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -4263,6 +4340,24 @@ static void def_node_image_user(StructRNA *srna)
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
RNA_def_property_ui_text(prop, "Layer", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_image_layer_update");
+
+ prop = RNA_def_property(srna, "has_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_layers_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has Layers", "True if this image has any named layer");
+
+ prop = RNA_def_property(srna, "view", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "view");
+ RNA_def_property_enum_items(prop, prop_image_view_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_image_view_itemf");
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ RNA_def_property_ui_text(prop, "View", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "has_views", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_views_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has View", "True if this image has multiple views");
}
static void def_cmp_image(StructRNA *srna)
@@ -5811,6 +5906,16 @@ 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)
+{
+ 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)
{
PropertyRNA *prop;
@@ -6294,14 +6399,12 @@ static void def_tex_image(StructRNA *srna)
RNA_def_property_ui_text(prop, "Image", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
- /* is this supposed to be exposed? not sure.. */
-#if 0
- prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "storage");
RNA_def_property_struct_type(prop, "ImageUser");
- RNA_def_property_ui_text(prop, "Settings", "");
+ RNA_def_property_ui_text(prop, "Image User",
+ "Parameters defining the image duration, offset and related settings");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-#endif
}
static void def_tex_bricks(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index d8aa659b68e..f433c2c36a8 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -46,7 +46,6 @@
#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_group.h" /* needed for BKE_group_object_exists() */
-#include "BKE_object.h" /* Needed for BKE_object_matrix_local_get() */
#include "BKE_object_deform.h"
#include "RNA_access.h"
@@ -88,8 +87,6 @@ EnumPropertyItem object_empty_drawtype_items[] = {
static EnumPropertyItem parent_type_items[] = {
{PAROBJECT, "OBJECT", 0, "Object", "The object is parented to an object"},
- {PARCURVE, "CURVE", 0, "Curve", "The object is parented to a curve"},
- {PARKEY, "KEY", 0, "Key", ""},
{PARSKEL, "ARMATURE", 0, "Armature", ""},
{PARSKEL, "LATTICE", 0, "Lattice", "The object is parented to a lattice"}, /* PARSKEL reuse will give issues */
{PARVERT1, "VERTEX", 0, "Vertex", "The object is parented to a vertex"},
@@ -202,7 +199,6 @@ EnumPropertyItem object_axis_unsigned_items[] = {
#include "BKE_scene.h"
#include "BKE_deform.h"
-#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_curve.h"
@@ -469,10 +465,7 @@ static EnumPropertyItem *rna_Object_parent_type_itemf(bContext *UNUSED(C), Point
if (ob->parent) {
Object *par = ob->parent;
- if (par->type == OB_CURVE) {
- RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARCURVE);
- }
- else if (par->type == OB_LATTICE) {
+ if (par->type == OB_LATTICE) {
/* special hack: prevents this overriding others */
RNA_enum_items_add_value(&item, &totitem, &parent_type_items[4], PARSKEL);
}
@@ -949,6 +942,7 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, ptr->id.data);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ DAG_relations_tag_update(bmain);
}
static char *rna_MaterialSlot_path(PointerRNA *ptr)
@@ -1009,7 +1003,7 @@ static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr)
static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->id.data;
- const int was_navmesh = (ob->gameflag & OB_NAVMESH);
+ const int gameflag_prev = ob->gameflag;
ob->body_type = value;
switch (ob->body_type) {
@@ -1067,7 +1061,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
break;
}
- if (was_navmesh != (ob->gameflag & OB_NAVMESH)) {
+ if ((gameflag_prev & OB_NAVMESH) != (ob->gameflag & OB_NAVMESH)) {
if (ob->type == OB_MESH) {
/* this is needed to refresh the derived meshes draw func */
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
@@ -1387,7 +1381,7 @@ static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
memcpy(values, bb->vec, sizeof(bb->vec));
}
else {
- fill_vn_fl(values, sizeof(bb->vec) / sizeof(float), 0.0f);
+ copy_vn_fl(values, sizeof(bb->vec) / sizeof(float), 0.0f);
}
}
@@ -1686,6 +1680,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "physics_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "body_type");
RNA_def_property_enum_items(prop, body_type_items);
+ RNA_def_property_enum_default(prop, OB_BODY_TYPE_STATIC);
RNA_def_property_enum_funcs(prop, "rna_GameObjectSettings_physics_type_get",
"rna_GameObjectSettings_physics_type_set", NULL);
RNA_def_property_ui_text(prop, "Physics Type", "Select the type of physical representation");
@@ -1705,12 +1700,14 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 10000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Mass", "Mass of the object");
prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "inertia");
RNA_def_property_range(prop, 0.01f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 10.0f, 1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Radius", "Radius of bounding sphere and material physics");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
@@ -1721,11 +1718,13 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "damping");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.04f);
RNA_def_property_ui_text(prop, "Damping", "General movement damping");
prop = RNA_def_property(srna, "rotation_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rdamping");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Rotation Damping", "General rotation damping");
prop = RNA_def_property(srna, "velocity_min", PROP_FLOAT, PROP_NONE);
@@ -1738,20 +1737,34 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_text(prop, "Velocity Max", "Clamp velocity to this maximum speed");
+ prop = RNA_def_property(srna, "angular_velocity_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "min_angvel");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_text(prop, "Angular Velocity Min",
+ "Clamp angular velocity to this minimum speed (except when totally still)");
+
+ prop = RNA_def_property(srna, "angular_velocity_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_angvel");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_text(prop, "Angular Velocity Max", "Clamp angular velocity to this maximum speed");
+
/* Character physics */
prop = RNA_def_property(srna, "step_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "step_height");
RNA_def_property_range(prop, 0.01, 1.0);
+ RNA_def_property_float_default(prop, 0.15f);
RNA_def_property_ui_text(prop, "Step Height", "Maximum height of steps the character can run over");
prop = RNA_def_property(srna, "jump_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "jump_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_text(prop, "Jump Force", "Upward velocity applied to the character when jumping");
prop = RNA_def_property(srna, "fall_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fall_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 55.0f);
RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall");
/* Collision Masks */
@@ -1812,6 +1825,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "form_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "formfactor");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.4f);
RNA_def_property_ui_text(prop, "Form Factor", "Form factor scales the inertia tensor");
prop = RNA_def_property(srna, "use_anisotropic_friction", PROP_BOOLEAN, PROP_NONE);
@@ -1844,6 +1858,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_margin", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "margin");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.04f);
RNA_def_property_ui_text(prop, "Collision Margin",
"Extra margin around object for collision detection, small amount required "
"for stability");
@@ -1859,6 +1874,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "obstacle_radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "obstacleRad");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Obstacle Radius", "Radius of object representation in obstacle simulation");
/* state */
@@ -2089,6 +2105,14 @@ static void rna_def_object_lodlevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Distance", "Distance to begin using this level of detail");
RNA_def_property_update(prop, NC_OBJECT | ND_LOD, "rna_Object_lod_distance_update");
+ prop = RNA_def_property(srna, "object_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "obhysteresis");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 10, 1);
+ RNA_def_property_ui_text(prop, "Hysteresis %",
+ "Minimum distance change required to transition to the previous level of detail");
+ RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "source");
RNA_def_property_struct_type(prop, "Object");
@@ -2107,6 +2131,11 @@ static void rna_def_object_lodlevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Material", "Use the material from this object at this level of detail");
RNA_def_property_ui_icon(prop, ICON_MATERIAL, 0);
RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+
+ prop = RNA_def_property(srna, "use_object_hysteresis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_HYST);
+ RNA_def_property_ui_text(prop, "Hysteresis Override", "Override LoD Hysteresis scene setting for this LoD level");
+ RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 2306682ca01..4b3f34f46c0 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -87,6 +87,8 @@ static EnumPropertyItem space_items[] = {
#include "MEM_guardedalloc.h"
+#include "DEG_depsgraph.h"
+
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
float *mat, float *mat_ret, int from, int to)
@@ -131,7 +133,7 @@ static void rna_Object_calc_matrix_camera(
static void rna_Object_camera_fit_coords(
Object *ob, Scene *scene, int num_cos, float *cos, float co_ret[3], float *scale_ret)
{
- BKE_camera_view_frame_fit_to_coords(scene, (float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
+ BKE_camera_view_frame_fit_to_coords(scene, (const float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
}
/* copied from Mesh_getFromObject and adapted to RNA interface */
@@ -191,8 +193,8 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e
static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings)
{
bool for_render = (settings == DAG_EVAL_RENDER);
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = settings;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, settings);
if (!(ob->transflag & OB_DUPLI)) {
BKE_report(reports, RPT_ERROR, "Object does not have duplis");
@@ -227,7 +229,7 @@ static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *
{
KeyBlock *kb = NULL;
- if ((kb = BKE_object_insert_shape_key(ob, name, from_mix))) {
+ if ((kb = BKE_object_shapekey_insert(ob, name, from_mix))) {
PointerRNA keyptr;
RNA_pointer_create((ID *)ob->data, &RNA_ShapeKey, kb, &keyptr);
@@ -241,6 +243,29 @@ static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *
}
}
+static void rna_Object_shape_key_remove(
+ Object *ob, Main *bmain, ReportList *reports,
+ PointerRNA *kb_ptr)
+{
+ KeyBlock *kb = kb_ptr->data;
+ Key *key = BKE_key_from_object(ob);
+
+ if ((key == NULL) || BLI_findindex(&key->block, kb) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "ShapeKey not found");
+ return;
+ }
+
+ if (!BKE_object_shapekey_remove(bmain, ob, kb)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not remove ShapeKey");
+ return;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+
+ RNA_POINTER_INVALIDATE(kb_ptr);
+}
+
static int rna_Object_is_visible(Object *ob, Scene *sce)
{
return !(ob->restrictflag & OB_RESTRICT_VIEW) && (ob->lay & sce->lay);
@@ -555,7 +580,7 @@ void RNA_api_object(StructRNA *srna)
/* Shape key */
func = RNA_def_function(srna, "shape_key_add", "rna_Object_shape_key_add");
- RNA_def_function_ui_description(func, "Add shape key to an object");
+ RNA_def_function_ui_description(func, "Add shape key to this object");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
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");
@@ -563,6 +588,13 @@ void RNA_api_object(StructRNA *srna)
RNA_def_property_flag(parm, PROP_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);
+
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast");
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 4cc098fb4a6..75becb341b9 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -845,7 +845,7 @@ static void rna_def_pointcache(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Cache is outdated", "");
- prop = RNA_def_property(srna, "frames_skipped", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
new file mode 100644
index 00000000000..8cbb57fde2c
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -0,0 +1,181 @@
+/*
+ * ***** 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/makesrna/intern/rna_palette.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "DNA_brush_types.h"
+
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+static PaletteColor *rna_Palette_color_new(Palette *palette)
+{
+ PaletteColor *color = BKE_palette_color_add(palette);
+ return color;
+}
+
+static void rna_Palette_color_remove(Palette *palette, ReportList *reports, PointerRNA *color_ptr)
+{
+ PaletteColor *color = color_ptr->data;
+
+ if (BLI_findindex(&palette->colors, color) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->id.name + 2);
+ return;
+ }
+
+ BKE_palette_color_remove(palette, color);
+
+ RNA_POINTER_INVALIDATE(color_ptr);
+}
+
+static void rna_Palette_color_clear(Palette *palette)
+{
+ BKE_palette_clear(palette);
+}
+
+static PointerRNA rna_Palette_active_color_get(PointerRNA *ptr)
+{
+ Palette *palette = ptr->data;
+ PaletteColor *color;
+
+ color = BLI_findlink(&palette->colors, palette->active_color);
+
+ if (color)
+ return rna_pointer_inherit_refine(ptr, &RNA_PaletteColor, color);
+
+ return rna_pointer_inherit_refine(ptr, NULL, NULL);
+}
+
+static void rna_Palette_active_color_set(PointerRNA *ptr, PointerRNA value)
+{
+ Palette *palette = ptr->data;
+ PaletteColor *color = value.data;
+
+ /* -1 is ok for an unset index */
+ if (color == NULL)
+ palette->active_color = -1;
+ else
+ palette->active_color = BLI_findindex(&palette->colors, color);
+}
+
+#else
+
+/* palette.colors */
+static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "PaletteColors");
+ srna = RNA_def_struct(brna, "PaletteColors", NULL);
+ RNA_def_struct_sdna(srna, "Palette");
+ RNA_def_struct_ui_text(srna, "Palette Splines", "Collection of palette colors");
+
+ func = RNA_def_function(srna, "new", "rna_Palette_color_new");
+ RNA_def_function_ui_description(func, "Add a new color to the palette");
+ parm = RNA_def_pointer(func, "color", "PaletteColor", "", "The newly created color");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Palette_color_remove");
+ 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);
+
+ func = RNA_def_function(srna, "clear", "rna_Palette_color_clear");
+ RNA_def_function_ui_description(func, "Remove all colors from the palette");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PaletteColor");
+ RNA_def_property_pointer_funcs(prop, "rna_Palette_active_color_get", "rna_Palette_active_color_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Palette Color", "");
+}
+
+static void rna_def_palettecolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "PaletteColor", NULL);
+ RNA_def_struct_ui_text(srna, "Palette Color", "");
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "value");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "value");
+ RNA_def_property_ui_text(prop, "Weight", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
+static void rna_def_palette(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Palette", "ID");
+ RNA_def_struct_ui_text(srna, "Palette", "");
+ RNA_def_struct_ui_icon(srna, ICON_COLOR);
+
+ prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PaletteColor");
+ rna_def_palettecolors(brna, prop);
+}
+
+void RNA_def_palette(BlenderRNA *brna)
+{
+ /* *** Non-Animated *** */
+ RNA_define_animate_sdna(false);
+ rna_def_palettecolor(brna);
+ rna_def_palette(brna);
+ RNA_define_animate_sdna(true);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 029563ad9c3..c0ce8f21870 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -2720,7 +2720,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "phase_factor_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "randphasefac");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_ui_text(prop, "Random Phase", "Randomize rotation around the chosen orientation axis");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 0428f5d8a9f..afbb97f519d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -109,8 +109,6 @@ EnumPropertyItem color_sets_items[] = {
#include "ED_object.h"
#include "ED_armature.h"
-#include "MEM_guardedalloc.h"
-
#include "WM_api.h"
#include "RNA_access.h"
@@ -231,7 +229,7 @@ static void rna_Pose_ik_solver_update(Main *bmain, Scene *UNUSED(scene), Pointer
Object *ob = ptr->id.data;
bPose *pose = ptr->data;
- pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ BKE_pose_tag_recalc(bmain, pose); /* checks & sorts pose channels */
DAG_relations_tag_update(bmain);
BKE_pose_update_constraint_flags(pose);
@@ -356,7 +354,7 @@ static void rna_Itasc_update_rebuild(Main *bmain, Scene *scene, PointerRNA *ptr)
Object *ob = ptr->id.data;
bPose *pose = ob->pose;
- pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ BKE_pose_tag_recalc(bmain, pose); /* checks & sorts pose channels */
rna_Itasc_update(bmain, scene, ptr);
}
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 124a83a5f30..61eb2c69bfe 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -76,6 +77,13 @@ EnumPropertyItem render_pass_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem 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}
+};
+
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@@ -153,8 +161,10 @@ static void engine_render(RenderEngine *engine, struct Scene *scene)
RNA_parameter_list_free(&list);
}
-static void engine_bake(RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type,
- const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result)
+static void engine_bake(RenderEngine *engine, struct Scene *scene,
+ struct Object *object, const int pass_type,
+ const int object_id, const struct BakePixel *pixel_array,
+ const int num_pixels, const int depth, void *result)
{
extern FunctionRNA rna_RenderEngine_bake_func;
PointerRNA ptr;
@@ -168,6 +178,7 @@ static void engine_bake(RenderEngine *engine, struct Scene *scene, struct Object
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
+ RNA_parameter_set_lookup(&list, "object_id", &object_id);
RNA_parameter_set_lookup(&list, "pixel_array", &pixel_array);
RNA_parameter_set_lookup(&list, "num_pixels", &num_pixels);
RNA_parameter_set_lookup(&list, "depth", &depth);
@@ -253,6 +264,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
+ dummyet.flag |= RE_USE_SHADING_NODES_CUSTOM;
RNA_pointer_create(NULL, &RNA_RenderEngine, &dummyengine, &dummyptr);
/* validate the python class */
@@ -322,38 +334,35 @@ static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
}
}
-static void rna_RenderResult_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static PointerRNA rna_RenderEngine_camera_override_get(PointerRNA *ptr)
{
- RenderResult *rr = (RenderResult *)ptr->data;
- rna_iterator_listbase_begin(iter, &rr->layers, NULL);
-}
+ RenderEngine *engine = (RenderEngine *)ptr->data;
-static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- RenderLayer *rl = (RenderLayer *)ptr->data;
- rna_iterator_listbase_begin(iter, &rl->passes, NULL);
+ if (engine->re) {
+ Object *cam = RE_GetCamera(engine->re);
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, cam);
+ }
+ else {
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, engine->camera_override);
+ }
}
-static int rna_RenderLayer_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static void rna_RenderResult_views_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- RenderLayer *rl = (RenderLayer *)ptr->data;
-
- length[0] = rl->rectx * rl->recty;
- length[1] = 4;
-
- return length[0] * length[1];
+ RenderResult *rr = (RenderResult *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rr->views, NULL);
}
-static void rna_RenderLayer_rect_get(PointerRNA *ptr, float *values)
+static void rna_RenderResult_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- RenderLayer *rl = (RenderLayer *)ptr->data;
- memcpy(values, rl->rectf, sizeof(float) * rl->rectx * rl->recty * 4);
+ RenderResult *rr = (RenderResult *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rr->layers, NULL);
}
-void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values)
+static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
RenderLayer *rl = (RenderLayer *)ptr->data;
- memcpy(rl->rectf, values, sizeof(float) * rl->rectx * rl->recty * 4);
+ rna_iterator_listbase_begin(iter, &rl->passes, NULL);
}
static int rna_RenderPass_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
@@ -384,6 +393,11 @@ static PointerRNA rna_BakePixel_next_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_BakePixel, bp + 1);
}
+static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view)
+{
+ return RE_pass_find_by_type(rl, passtype, view);
+}
+
#else /* RNA_RUNTIME */
static void rna_def_render_engine(BlenderRNA *brna)
@@ -420,6 +434,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_enum(func, "pass_type", render_pass_type_items, 0, "Pass", "Pass to bake");
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);
@@ -467,6 +483,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_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);
@@ -487,6 +504,22 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_boolean(func, "do_break", 0, "Break", "");
RNA_def_function_return(func, prop);
+ 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);
+
+ 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_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
+ RNA_def_function_return(func, prop);
+
+ 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_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);
+
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", "");
@@ -548,7 +581,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_PREVIEW);
prop = RNA_def_property(srna, "camera_override", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "camera_override");
+ RNA_def_property_pointer_funcs(prop, "rna_RenderEngine_camera_override_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "Object");
prop = RNA_def_property(srna, "layer_override", PROP_BOOLEAN, PROP_LAYER_MEMBER);
@@ -603,6 +636,11 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SHADING_NODES);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_use_shading_nodes_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SHADING_NODES_CUSTOM);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
prop = RNA_def_property(srna, "bl_use_exclude_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_EXCLUDE_LAYERS);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
@@ -647,9 +685,56 @@ static void rna_def_render_result(BlenderRNA *brna)
"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",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+
+ RNA_define_verify_sdna(1);
+}
+
+static void rna_def_render_view(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "RenderView", NULL);
+ RNA_def_struct_ui_text(srna, "Render View", "");
+
+ RNA_define_verify_sdna(0);
+
+ 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);
+ RNA_def_struct_name_property(srna, prop);
+
RNA_define_verify_sdna(1);
}
+static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "RenderPasses");
+ srna = RNA_def_struct(brna, "RenderPasses", NULL);
+ RNA_def_struct_sdna(srna, "RenderLayer");
+ RNA_def_struct_ui_text(srna, "Render Passes", "Collection of render passes");
+
+ 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", render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
+ RNA_def_property_flag(parm, PROP_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);
+ 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;
@@ -679,12 +764,7 @@ static void rna_def_render_layer(BlenderRNA *brna)
RNA_def_property_collection_funcs(prop, "rna_RenderLayer_passes_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
-
- 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);
- RNA_def_property_dynamic_array_funcs(prop, "rna_RenderLayer_rect_get_length");
- RNA_def_property_float_funcs(prop, "rna_RenderLayer_rect_get", "rna_RenderLayer_rect_set", NULL);
+ rna_def_render_passes(brna, prop);
RNA_define_verify_sdna(1);
}
@@ -694,11 +774,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem render_pass_debug_type_items[] = {
- {RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, "BVH_TRAVERSAL_STEPS", 0, "BVH Traversal Steps", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "RenderPass", NULL);
RNA_def_struct_ui_text(srna, "Render Pass", "");
@@ -728,6 +803,10 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_dynamic_array_funcs(prop, "rna_RenderPass_rect_get_length");
RNA_def_property_float_funcs(prop, "rna_RenderPass_rect_get", "rna_RenderPass_rect_set", NULL);
+ prop = RNA_def_property(srna, "view_id", PROP_INT, PROP_NONE);
+ 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, render_pass_debug_type_items);
@@ -750,6 +829,10 @@ static void rna_def_render_bake_pixel(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "primitive_id");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "object_id", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "object_id");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_float_sdna(prop, NULL, "uv");
@@ -783,6 +866,7 @@ void RNA_def_render(BlenderRNA *brna)
{
rna_def_render_engine(brna);
rna_def_render_result(brna);
+ rna_def_render_view(brna);
rna_def_render_layer(brna);
rna_def_render_pass(brna);
rna_def_render_bake_pixel(brna);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 42e231fa76f..4650e27f63e 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -105,7 +105,6 @@ EnumPropertyItem property_unit_items[] = {
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
#include "BLI_ghash.h"
/* Struct */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 3e7ffcd8cf0..d61f734e19c 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -36,14 +36,16 @@
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
+#include "IMB_imbuf_types.h"
+
#include "BLI_math.h"
#include "BLF_translation.h"
-#include "BKE_freestyle.h"
#include "BKE_editmesh.h"
#include "BKE_paint.h"
-#include "BKE_scene.h"
+
+#include "GPU_extensions.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -130,6 +132,7 @@ EnumPropertyItem proportional_falloff_curve_only_items[] = {
{PROP_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "Smooth falloff"},
{PROP_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", "Spherical falloff"},
{PROP_ROOT, "ROOT", ICON_ROOTCURVE, "Root", "Root falloff"},
+ {PROP_INVSQUARE, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", "Inverse Square falloff"},
{PROP_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", "Sharp falloff"},
{PROP_LIN, "LINEAR", ICON_LINCURVE, "Linear", "Linear falloff"},
{0, NULL, 0, NULL, NULL}
@@ -155,7 +158,10 @@ EnumPropertyItem mesh_select_mode_items[] = {
};
EnumPropertyItem snap_element_items[] = {
- {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
+ {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_ALIGN, "Grid (increment)", "Snap to increments of grid"},
+#if 0
+ {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_INCREMENT, "Grid (absolute)", "Snap to grid"},
+#endif
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
{SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap to faces"},
@@ -215,13 +221,13 @@ EnumPropertyItem snap_uv_element_items[] = {
#endif
#ifdef WITH_OPENEXR
-# define R_IMF_ENUM_EXR_MULTI {R_IMF_IMTYPE_MULTILAYER, "OPEN_EXR_MULTILAYER", ICON_FILE_IMAGE, \
+# define R_IMF_ENUM_EXR_MULTILAYER {R_IMF_IMTYPE_MULTILAYER, "OPEN_EXR_MULTILAYER", ICON_FILE_IMAGE, \
"OpenEXR MultiLayer", \
"Output image in multilayer OpenEXR format"},
# define R_IMF_ENUM_EXR {R_IMF_IMTYPE_OPENEXR, "OPEN_EXR", ICON_FILE_IMAGE, "OpenEXR", \
"Output image in OpenEXR format"},
#else
-# define R_IMF_ENUM_EXR_MULTI
+# define R_IMF_ENUM_EXR_MULTILAYER
# define R_IMF_ENUM_EXR
#endif
@@ -250,7 +256,7 @@ EnumPropertyItem snap_uv_element_items[] = {
{0, "", 0, " ", NULL}, \
R_IMF_ENUM_CINEON \
R_IMF_ENUM_DPX \
- R_IMF_ENUM_EXR_MULTI \
+ R_IMF_ENUM_EXR_MULTILAYER \
R_IMF_ENUM_EXR \
R_IMF_ENUM_HDR \
R_IMF_ENUM_TIFF \
@@ -334,6 +340,62 @@ EnumPropertyItem bake_save_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#define R_IMF_VIEWS_ENUM_IND {R_IMF_VIEWS_INDIVIDUAL, "INDIVIDUAL", 0, "Individual", \
+ "Individual files for each view with the prefix as defined by the scene views"},
+#define R_IMF_VIEWS_ENUM_S3D {R_IMF_VIEWS_STEREO_3D, "STEREO_3D", 0, "Stereo 3D", \
+ "Single file with an encoded stereo pair"},
+#define R_IMF_VIEWS_ENUM_MV {R_IMF_VIEWS_MULTIVIEW, "MULTIVIEW", 0, "Multi-View", "Single file with all the views"},
+
+EnumPropertyItem views_format_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem views_format_multilayer_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_MV
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem views_format_multiview_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_S3D
+ R_IMF_VIEWS_ENUM_MV
+ {0, NULL, 0, NULL, NULL}
+};
+
+#undef R_IMF_VIEWS_ENUM_IND
+#undef R_IMF_VIEWS_ENUM_S3D
+#undef R_IMF_VIEWS_ENUM_MV
+
+EnumPropertyItem stereo3d_display_items[] = {
+ {S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
+ "Render views for left and right eyes as two differently filtered colors in a single image "
+ "(anaglyph glasses are required)"},
+ {S3D_DISPLAY_INTERLACE, "INTERLACE", 0, "Interlace",
+ "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
+ {S3D_DISPLAY_PAGEFLIP, "TIMESEQUENTIAL", 0, "Time Sequential",
+ "Render alternate eyes (also known as page flip, quad buffer support in the graphic card is required)"},
+ {S3D_DISPLAY_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-Side", "Render views for left and right eyes side-by-side"},
+ {S3D_DISPLAY_TOPBOTTOM, "TOPBOTTOM", 0, "Top-Bottom", "Render views for left and right eyes one above another"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem stereo3d_anaglyph_type_items[] = {
+ {S3D_ANAGLYPH_REDCYAN, "RED_CYAN", 0, "Red-Cyan", ""},
+ {S3D_ANAGLYPH_GREENMAGENTA, "GREEN_MAGENTA", 0, "Green-Magenta", ""},
+ {S3D_ANAGLYPH_YELLOWBLUE, "YELLOW_BLUE", 0, "Yellow-Blue", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem stereo3d_interlace_type_items[] = {
+ {S3D_INTERLACE_ROW, "ROW_INTERLEAVED", 0, "Row Interleaved", ""},
+ {S3D_INTERLACE_COLUMN, "COLUMN_INTERLEAVED", 0, "Column Interleaved", ""},
+ {S3D_INTERLACE_CHECKERBOARD, "CHECKERBOARD_INTERLEAVED", 0, "Checkerboard Interleaved", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@@ -346,8 +408,6 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "MEM_guardedalloc.h"
-#include "BLI_threads.h"
-
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -357,7 +417,6 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_depsgraph.h"
-#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
@@ -365,8 +424,6 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "BKE_animsys.h"
#include "BKE_freestyle.h"
-#include "WM_api.h"
-
#include "ED_info.h"
#include "ED_node.h"
#include "ED_view3d.h"
@@ -374,8 +431,6 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "ED_keyframing.h"
#include "ED_image.h"
-#include "RE_engine.h"
-
#ifdef WITH_FREESTYLE
#include "FRS_freestyle.h"
#endif
@@ -538,13 +593,13 @@ static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- sound_update_fps(scene);
+ BKE_sound_update_fps(scene);
BKE_sequencer_update_sound_bounds_all(scene);
}
static void rna_Scene_listener_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- sound_update_scene_listener(scene);
+ BKE_sound_update_scene_listener(scene);
}
static void rna_Scene_volume_set(PointerRNA *ptr, float value)
@@ -553,7 +608,7 @@ static void rna_Scene_volume_set(PointerRNA *ptr, float value)
scene->audio.volume = value;
if (scene->sound_scene)
- sound_set_scene_volume(scene, value);
+ BKE_sound_set_scene_volume(scene, value);
}
static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -654,7 +709,7 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
}
static PointerRNA rna_Scene_active_keying_set_get(PointerRNA *ptr)
@@ -721,6 +776,26 @@ static void rna_Scene_all_keyingsets_next(CollectionPropertyIterator *iter)
iter->valid = (internal->link != NULL);
}
+static int rna_RenderSettings_stereoViews_skip(CollectionPropertyIterator *iter, void *UNUSED(data))
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+ SceneRenderView *srv = (SceneRenderView *)internal->link;
+
+ if ((STREQ(srv->name, STEREO_LEFT_NAME)) ||
+ (STREQ(srv->name, STEREO_RIGHT_NAME)))
+ {
+ return 0;
+ }
+
+ return 1;
+};
+
+static void rna_RenderSettings_stereoViews_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rd->views, rna_RenderSettings_stereoViews_skip);
+}
+
static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
{
return BLI_sprintfN("render");
@@ -823,8 +898,8 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
ID *id = ptr->id.data;
if (id && GS(id->name) == ID_SCE) {
@@ -835,8 +910,8 @@ static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *UNU
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
@@ -880,8 +955,8 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *UNUS
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -943,11 +1018,30 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNU
}
}
+static EnumPropertyItem *rna_ImageFormatSettings_views_format_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+
+ if (imf == NULL) {
+ return views_format_items;
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_OPENEXR) {
+ return views_format_multiview_items;
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ return views_format_multilayer_items;
+ }
+ else {
+ return views_format_items;
+ }
+}
+
#ifdef WITH_OPENEXR
/* OpenEXR */
-static EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(bContext *UNUSED(C), PointerRNA *ptr,
-PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -1003,8 +1097,8 @@ static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, in
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)
+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, "", ""};
@@ -1041,8 +1135,8 @@ static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *pt
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)
+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, "", ""};
@@ -1102,8 +1196,8 @@ static void rna_RenderSettings_active_layer_index_set(PointerRNA *ptr, int value
rd->actlay = min_ff(value, num_layers - 1);
}
-static void rna_RenderSettings_active_layer_index_range(PointerRNA *ptr, int *min, int *max,
- int *UNUSED(softmin), int *UNUSED(softmax))
+static void rna_RenderSettings_active_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1138,8 +1232,8 @@ static SceneRenderLayer *rna_RenderLayer_new(ID *id, RenderData *UNUSED(rd), con
return srl;
}
-static void rna_RenderLayer_remove(ID *id, RenderData *UNUSED(rd), Main *bmain, ReportList *reports,
- PointerRNA *srl_ptr)
+static void rna_RenderLayer_remove(
+ ID *id, RenderData *UNUSED(rd), Main *bmain, ReportList *reports, PointerRNA *srl_ptr)
{
SceneRenderLayer *srl = srl_ptr->data;
Scene *scene = (Scene *)id;
@@ -1156,6 +1250,70 @@ static void rna_RenderLayer_remove(ID *id, RenderData *UNUSED(rd), Main *bmain,
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
+static int rna_RenderSettings_active_view_index_get(PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ return rd->actview;
+}
+
+static void rna_RenderSettings_active_view_index_set(PointerRNA *ptr, int value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ rd->actview = value;
+}
+
+static void rna_RenderSettings_active_view_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ RenderData *rd = (RenderData *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&rd->views) - 1);
+}
+
+static PointerRNA rna_RenderSettings_active_view_get(PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ SceneRenderView *srv = BLI_findlink(&rd->views, rd->actview);
+
+ return rna_pointer_inherit_refine(ptr, &RNA_SceneRenderView, srv);
+}
+
+static void rna_RenderSettings_active_view_set(PointerRNA *ptr, PointerRNA value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ SceneRenderView *srv = (SceneRenderView *)value.data;
+ const int index = BLI_findindex(&rd->views, srv);
+ if (index != -1) rd->actview = index;
+}
+
+static SceneRenderView *rna_RenderView_new(ID *id, RenderData *UNUSED(rd), const char *name)
+{
+ Scene *scene = (Scene *)id;
+ SceneRenderView *srv = BKE_scene_add_render_view(scene, name);
+
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ return srv;
+}
+
+static void rna_RenderView_remove(
+ ID *id, RenderData *UNUSED(rd), Main *UNUSED(bmain), ReportList *reports, PointerRNA *srv_ptr)
+{
+ SceneRenderView *srv = srv_ptr->data;
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_scene_remove_render_view(scene, srv)) {
+ BKE_reportf(reports, RPT_ERROR, "Render view '%s' could not be removed from scene '%s'",
+ srv->name, scene->id.name + 2);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(srv_ptr);
+
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
static void rna_RenderSettings_engine_set(PointerRNA *ptr, int value)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1165,8 +1323,8 @@ static void rna_RenderSettings_engine_set(PointerRNA *ptr, int value)
BLI_strncpy_utf8(rd->engine, type->idname, sizeof(rd->engine));
}
-static EnumPropertyItem *rna_RenderSettings_engine_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_RenderSettings_engine_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
RenderEngineType *type;
EnumPropertyItem *item = NULL;
@@ -1249,7 +1407,7 @@ static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "render.layers", oldname, rl->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "render.layers", oldname, rl->name);
}
static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
@@ -1261,6 +1419,34 @@ static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
return BLI_sprintfN("render.layers[\"%s\"]", name_esc);
}
+static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneRenderView *rv = (SceneRenderView *)ptr->data;
+ BLI_strncpy_utf8(rv->name, value, sizeof(rv->name));
+ BLI_uniquename(&scene->r.views, rv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(rv->name));
+}
+
+static char *rna_SceneRenderView_path(PointerRNA *ptr)
+{
+ SceneRenderView *srv = (SceneRenderView *)ptr->data;
+ return BLI_sprintfN("render.views[\"%s\"]", srv->name);
+}
+
+static void rna_RenderSettings_views_format_set(PointerRNA *ptr, int value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW &&
+ value == SCE_VIEWS_FORMAT_STEREO_3D)
+ {
+ /* make sure the actview is visible */
+ if (rd->actview > 1) rd->actview = 1;
+ }
+
+ rd->views_format = value;
+}
+
static int rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr))
{
return (BLI_listbase_count(&R_engines) > 1);
@@ -1422,7 +1608,7 @@ static void rna_Scene_use_audio_set(PointerRNA *ptr, int value)
else
scene->audio.flag &= ~AUDIO_MUTE;
- sound_mute_scene(scene, value);
+ BKE_sound_mute_scene(scene, value);
}
static int rna_Scene_sync_mode_get(PointerRNA *ptr)
@@ -1636,10 +1822,11 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value
lineset->linestyle->id.us++;
}
-static FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, FreestyleSettings *config, const char *name)
+static FreestyleLineSet *rna_FreestyleSettings_lineset_add(
+ ID *id, FreestyleSettings *config, Main *bmain, const char *name)
{
Scene *scene = (Scene *)id;
- FreestyleLineSet *lineset = BKE_freestyle_lineset_add((FreestyleConfig *)config, name);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_add(bmain, (FreestyleConfig *)config, name);
DAG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -1647,8 +1834,8 @@ static FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, FreestyleSett
return lineset;
}
-static void rna_FreestyleSettings_lineset_remove(ID *id, FreestyleSettings *config, ReportList *reports,
- PointerRNA *lineset_ptr)
+static void rna_FreestyleSettings_lineset_remove(
+ ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *lineset_ptr)
{
FreestyleLineSet *lineset = lineset_ptr->data;
Scene *scene = (Scene *)id;
@@ -1671,8 +1858,8 @@ static PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineSet, lineset);
}
-static void rna_FreestyleSettings_active_lineset_index_range(PointerRNA *ptr, int *min, int *max,
- int *UNUSED(softmin), int *UNUSED(softmax))
+static void rna_FreestyleSettings_active_lineset_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
@@ -1703,8 +1890,8 @@ static FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, Freestyle
return module;
}
-static void rna_FreestyleSettings_module_remove(ID *id, FreestyleSettings *config, ReportList *reports,
- PointerRNA *module_ptr)
+static void rna_FreestyleSettings_module_remove(
+ ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *module_ptr)
{
Scene *scene = (Scene *)id;
FreestyleModuleConfig *module = module_ptr->data;
@@ -1713,7 +1900,7 @@ static void rna_FreestyleSettings_module_remove(ID *id, FreestyleSettings *confi
if (module->script)
BKE_reportf(reports, RPT_ERROR, "Style module '%s' could not be removed", module->script->id.name + 2);
else
- BKE_reportf(reports, RPT_ERROR, "Style module could not be removed");
+ BKE_report(reports, RPT_ERROR, "Style module could not be removed");
return;
}
@@ -1735,7 +1922,7 @@ char *rna_GPUDOF_path(PointerRNA *ptr)
}
}
- return BLI_strdup("");;
+ return BLI_strdup("");
}
static void rna_GPUFXSettings_fx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -1745,6 +1932,44 @@ static void rna_GPUFXSettings_fx_update(Main *UNUSED(bmain), Scene *UNUSED(scene
BKE_screen_gpu_fx_validate(fx_settings);
}
+static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value)
+{
+ GPUDOFSettings *dofsettings = (GPUDOFSettings *)ptr->data;
+
+ if (value < 3 && dofsettings->num_blades > 2)
+ dofsettings->num_blades = 0;
+ else if (value > 0 && dofsettings->num_blades == 0)
+ dofsettings->num_blades = 3;
+ else
+ dofsettings->num_blades = value;
+}
+
+static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+
+ if (id && GS(id->name) == ID_IM) {
+ Image *ima = (Image *)id;
+ ImBuf *ibuf;
+ void *lock;
+
+ if ((ima->flag & IMA_IS_STEREO) == 0)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
+ }
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+}
+
+static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
+{
+ return GPU_instanced_drawing_support() && GPU_geometry_shader_support();
+}
+
#else
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -1830,9 +2055,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
static EnumPropertyItem gpencil_source_3d_items[] = {
{GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
- "Grease Pencil data attached to the current scene is used, unless the active object already has Grease Pencil data (i.e. for old files)"},
+ "Grease Pencil data attached to the current scene is used, "
+ "unless the active object already has Grease Pencil data (i.e. for old files)"},
{GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object",
- "Grease Pencil datablocks attached to the active object are used (required using pre 2.73 add-ons, e.g. BSurfaces)"},
+ "Grease Pencil datablocks attached to the active object are used "
+ "(required using pre 2.73 add-ons, e.g. BSurfaces)"},
{0, NULL, 0, NULL, NULL}
};
@@ -1934,6 +2161,22 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_proportional_action", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proportional_action", 0);
+ RNA_def_property_ui_text(prop, "Proportional Editing Actions", "Proportional editing in action editor");
+ RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_proportional_fcurve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proportional_fcurve", 0);
+ RNA_def_property_ui_text(prop, "Proportional Editing FCurves", "Proportional editing in FCurve editor");
+ RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "lock_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "lock_markers", 0);
+ RNA_def_property_ui_text(prop, "Lock Markers", "Prevent marker editing");
+
prop = RNA_def_property(srna, "proportional_edit_falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "prop_mode");
RNA_def_property_enum_items(prop, proportional_falloff_items);
@@ -2114,7 +2357,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_etch_autoname", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "skgen_retarget_options", SK_RETARGET_AUTONAME);
- RNA_def_property_ui_text(prop, "Autoname Bones", "Automatically generate values to replace &N and &S suffix placeholders in template names");
+ RNA_def_property_ui_text(prop, "Autoname Bones",
+ "Automatically generate values to replace &N and &S suffix placeholders in template names");
prop = RNA_def_property(srna, "etch_number", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "skgen_num_string");
@@ -2841,7 +3085,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_FreestyleSettings_lineset_add");
RNA_def_function_ui_description(func, "Add a line set to scene render layer Freestyle settings");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ 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);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set");
@@ -3002,12 +3246,14 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "face_mark_condition", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, face_mark_condition_items);
- RNA_def_property_ui_text(prop, "Face Mark Condition", "Specify a feature edge selection condition based on face marks");
+ RNA_def_property_ui_text(prop, "Face Mark Condition",
+ "Specify a feature edge selection condition based on face marks");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_silhouette", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SILHOUETTE);
- RNA_def_property_ui_text(prop, "Silhouette", "Select silhouettes (edges at the boundary of visible and hidden faces)");
+ RNA_def_property_ui_text(prop, "Silhouette",
+ "Select silhouettes (edges at the boundary of visible and hidden faces)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_border", PROP_BOOLEAN, PROP_NONE);
@@ -3017,12 +3263,14 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CREASE);
- RNA_def_property_ui_text(prop, "Crease", "Select crease edges (those between two faces making an angle smaller than the Crease Angle)");
+ RNA_def_property_ui_text(prop, "Crease",
+ "Select crease edges (those between two faces making an angle smaller than the Crease Angle)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_ridge_valley", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_RIDGE_VALLEY);
- RNA_def_property_ui_text(prop, "Ridge & Valley", "Select ridges and valleys (boundary lines between convex and concave areas of surface)");
+ RNA_def_property_ui_text(prop, "Ridge & Valley",
+ "Select ridges and valleys (boundary lines between convex and concave areas of surface)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_suggestive_contour", PROP_BOOLEAN, PROP_NONE);
@@ -3042,7 +3290,8 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_external_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR);
- RNA_def_property_ui_text(prop, "External Contour", "Select external contours (outer silhouettes of occluding and occluded objects)");
+ RNA_def_property_ui_text(prop, "External Contour",
+ "Select external contours (outer silhouettes of occluding and occluded objects)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_edge_mark", PROP_BOOLEAN, PROP_NONE);
@@ -3191,7 +3440,8 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_view_map_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_VIEW_MAP_CACHE);
- RNA_def_property_ui_text(prop, "View Map Cache", "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged");
+ RNA_def_property_ui_text(prop, "View Map Cache",
+ "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_use_view_map_cache_update");
prop = RNA_def_property(srna, "sphere_radius", PROP_FLOAT, PROP_NONE);
@@ -3232,36 +3482,42 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cellsize");
RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
+ RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(prop, "Cell Size", "Rasterized cell size");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "cell_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cellheight");
RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
+ RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Cell Height", "Rasterized cell height");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "agent_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentheight");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 2.0f);
RNA_def_property_ui_text(prop, "Agent Height", "Minimum height where the agent can still walk");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "agent_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentradius");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 0.6f);
RNA_def_property_ui_text(prop, "Agent Radius", "Radius of the agent");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "climb_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentmaxclimb");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 0.9f);
RNA_def_property_ui_text(prop, "Max Climb", "Maximum height between grid cells the agent can climb");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "agentmaxslope");
RNA_def_property_range(prop, 0, M_PI_2);
+ RNA_def_property_float_default(prop, M_PI_4);
RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3269,42 +3525,49 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "region_min_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "regionminsize");
RNA_def_property_ui_range(prop, 0, 150, 1, 2);
+ RNA_def_property_float_default(prop, 8.0f);
RNA_def_property_ui_text(prop, "Min Region Size", "Minimum regions size (smaller regions will be deleted)");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "region_merge_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "regionmergesize");
RNA_def_property_ui_range(prop, 0, 150, 1, 2);
+ RNA_def_property_float_default(prop, 20.0f);
RNA_def_property_ui_text(prop, "Merged Region Size", "Minimum regions size (smaller regions will be merged)");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "edge_max_len", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "edgemaxlen");
RNA_def_property_ui_range(prop, 0, 50, 1, 2);
+ RNA_def_property_float_default(prop, 12.0f);
RNA_def_property_ui_text(prop, "Max Edge Length", "Maximum contour edge length");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "edge_max_error", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "edgemaxerror");
RNA_def_property_ui_range(prop, 0.1, 3.0, 1, 2);
+ RNA_def_property_float_default(prop, 1.3f);
RNA_def_property_ui_text(prop, "Max Edge Error", "Maximum distance error from contour to cells");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "verts_per_poly", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "vertsperpoly");
RNA_def_property_ui_range(prop, 3, 12, 1, -1);
+ RNA_def_property_int_default(prop, 6);
RNA_def_property_ui_text(prop, "Verts Per Poly", "Max number of vertices per polygon");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "sample_dist", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "detailsampledist");
RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
+ RNA_def_property_float_default(prop, 6.0f);
RNA_def_property_ui_text(prop, "Sample Distance", "Detail mesh sample spacing");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "sample_max_error", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "detailsamplemaxerror");
RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Max Sample Error", "Detail mesh simplification max sample error");
RNA_def_property_update(prop, NC_SCENE, NULL);
}
@@ -3516,12 +3779,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "xplay");
RNA_def_property_range(prop, 4, 10000);
+ RNA_def_property_int_default(prop, 640);
RNA_def_property_ui_text(prop, "Resolution X", "Number of horizontal pixels in the screen");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "yplay");
RNA_def_property_range(prop, 4, 10000);
+ RNA_def_property_int_default(prop, 480);
RNA_def_property_ui_text(prop, "Resolution Y", "Number of vertical pixels in the screen");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3538,12 +3803,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "depth");
RNA_def_property_range(prop, 8, 32);
+ RNA_def_property_int_default(prop, 32);
RNA_def_property_ui_text(prop, "Bits", "Display bit depth of full screen display");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "exitkey");
RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_default(prop, ESCKEY);
RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL);
RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3558,6 +3825,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "freqplay");
RNA_def_property_range(prop, 4, 2000);
+ RNA_def_property_int_default(prop, 60);
RNA_def_property_ui_text(prop, "Freq", "Display clock frequency of fullscreen display");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3595,12 +3863,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "stereo_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "stereomode");
RNA_def_property_enum_items(prop, stereo_modes_items);
+ RNA_def_property_enum_default(prop, STEREO_ANAGLYPH);
RNA_def_property_ui_text(prop, "Stereo Mode", "Stereographic techniques");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "stereo_eye_separation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "eyeseparation");
RNA_def_property_range(prop, 0.01, 5.0);
+ RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Eye Separation",
"Set the distance between the eyes - the camera focal distance/30 should be fine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3615,18 +3885,21 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "dome_tessellation", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dome.res");
RNA_def_property_ui_range(prop, 1, 8, 1, 1);
+ RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Tessellation", "Tessellation level - check the generated mesh in wireframe mode");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "dome_buffer_resolution", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dome.resbuf");
RNA_def_property_ui_range(prop, 0.1, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Buffer Resolution", "Buffer Resolution - decrease it to increase speed");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "dome_angle", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dome.angle");
RNA_def_property_ui_range(prop, 90, 250, 1, 1);
+ RNA_def_property_int_default(prop, 180);
RNA_def_property_ui_text(prop, "Angle", "Field of View of the Dome - it only works in mode Fisheye and Truncated");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3647,6 +3920,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "physics_engine", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "physicsEngine");
RNA_def_property_enum_items(prop, physics_engine_items);
+ RNA_def_property_enum_default(prop, WOPHY_BULLET);
RNA_def_property_ui_text(prop, "Physics Engine", "Physics engine used for physics simulation in the game engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3654,6 +3928,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "gravity");
RNA_def_property_ui_range(prop, 0.0, 25.0, 1, 2);
RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_float_default(prop, 9.8f);
RNA_def_property_ui_text(prop, "Physics Gravity",
"Gravitational constant used for physics simulation in the game engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3661,6 +3936,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "occlusion_culling_resolution", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "occlusionRes");
RNA_def_property_range(prop, 128.0, 1024.0);
+ RNA_def_property_int_default(prop, 128);
RNA_def_property_ui_text(prop, "Occlusion Resolution",
"Size of the occlusion buffer, use higher value for better precision (slower)");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3669,6 +3945,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "ticrate");
RNA_def_property_ui_range(prop, 1, 60, 1, 1);
RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_int_default(prop, 60);
RNA_def_property_ui_text(prop, "Frames Per Second",
"Nominal number of game frames per second "
"(physics fixed timestep = 1/fps, independently of actual frame rate)");
@@ -3678,6 +3955,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "maxlogicstep");
RNA_def_property_range(prop, 1, 10000);
RNA_def_property_ui_range(prop, 1, 50, 1, 1);
+ RNA_def_property_int_default(prop, 5);
RNA_def_property_ui_text(prop, "Max Logic Steps",
"Maximum number of logic frame per game frame if graphics slows down the game, "
"higher value allows better synchronization with physics");
@@ -3687,6 +3965,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "maxphystep");
RNA_def_property_range(prop, 1, 10000);
RNA_def_property_ui_range(prop, 1, 50, 1, 1);
+ RNA_def_property_int_default(prop, 5);
RNA_def_property_ui_text(prop, "Max Physics Steps",
"Maximum number of physics step per game frame if graphics slows down the game, "
"higher value allows physics to keep up with realtime");
@@ -3696,6 +3975,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "physubstep");
RNA_def_property_range(prop, 1, 50);
RNA_def_property_ui_range(prop, 1, 5, 1, 1);
+ RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_text(prop, "Physics Sub Steps",
"Number of simulation substep per physic timestep, "
"higher value give better physics precision");
@@ -3705,6 +3985,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "lineardeactthreshold");
RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Deactivation Linear Threshold",
"Linear velocity that an object must be below before the deactivation timer can start");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3713,6 +3994,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "angulardeactthreshold");
RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Deactivation Angular Threshold",
"Angular velocity that an object must be below before the deactivation timer can start");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3856,6 +4138,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "level_height", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "levelHeight");
RNA_def_property_range(prop, 0.0f, 200.0f);
+ RNA_def_property_float_default(prop, 2.0f);
RNA_def_property_ui_text(prop, "Level height",
"Max difference in heights of obstacles to enable their interaction");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3873,6 +4156,21 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
/* Nestled Data */
rna_def_scene_game_recast_data(brna);
+
+ /* LoD */
+ prop = RNA_def_property(srna, "use_scene_hysteresis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "lodflag", SCE_LOD_USE_HYST);
+ RNA_def_property_ui_text(prop, "Hysteresis", "Use LoD Hysteresis setting for the scene");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "scene_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "scehysteresis");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 10, 1);
+ RNA_def_property_int_default(prop, 10);
+ RNA_def_property_ui_text(prop, "Hysteresis %",
+ "Minimum distance change required to transition to the previous level of detail");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
}
static void rna_def_gpu_dof_fx(BlenderRNA *brna)
@@ -3904,10 +4202,28 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "fstop", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Viewport F-stop", "F-stop for dof effect");
+ RNA_def_property_ui_text(prop, "F-stop", "F-stop for dof effect");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "blades", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "num_blades");
+ RNA_def_property_ui_text(prop, "Blades", "Blades for dof effect");
+ RNA_def_property_range(prop, 0, 16);
+ RNA_def_property_int_funcs(prop, NULL, "rna_GPUDOFSettings_blades_set", NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_high_quality", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "high_quality", 1);
+ RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "is_hq_supported", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_gpu_is_hq_supported_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_gpu_ssao_fx(BlenderRNA *brna)
@@ -3967,7 +4283,8 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_DOF);
- RNA_def_property_ui_text(prop, "Depth Of Field", "Use depth of field on viewport using the values from active camera");
+ RNA_def_property_ui_text(prop, "Depth Of Field",
+ "Use depth of field on viewport using the values from active camera");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update");
@@ -4051,6 +4368,138 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
+/* Render Views - MultiView */
+static void rna_def_scene_render_view(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SceneRenderView", NULL);
+ RNA_def_struct_ui_text(srna, "Scene Render View", "Render viewpoint for 3D stereo and multiview rendering");
+ RNA_def_struct_ui_icon(srna, ICON_RESTRICT_RENDER_OFF);
+ RNA_def_struct_path_func(srna, "rna_SceneRenderView_path");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneRenderView_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Render view name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "file_suffix", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "suffix");
+ RNA_def_property_ui_text(prop, "File Suffix", "Suffix added to the render images for this view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "camera_suffix", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "suffix");
+ RNA_def_property_ui_text(prop, "Camera Suffix",
+ "Suffix to identify the cameras to use, and added to the render images for this view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "viewflag", SCE_VIEW_DISABLE);
+ RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
+static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "RenderViews");
+ srna = RNA_def_struct(brna, "RenderViews", NULL);
+ RNA_def_struct_sdna(srna, "RenderData");
+ RNA_def_struct_ui_text(srna, "Render Views", "Collection of render views");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "actview");
+ RNA_def_property_int_funcs(prop, "rna_RenderSettings_active_view_index_get",
+ "rna_RenderSettings_active_view_index_set",
+ "rna_RenderSettings_active_view_index_range");
+ RNA_def_property_ui_text(prop, "Active View Index", "Active index in render view array");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_pointer_funcs(prop, "rna_RenderSettings_active_view_get",
+ "rna_RenderSettings_active_view_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Active Render View", "Active Render View");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ func = RNA_def_function(srna, "new", "rna_RenderView_new");
+ 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);
+ parm = RNA_def_pointer(func, "result", "SceneRenderView", "", "Newly created render view");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_RenderView_remove");
+ 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);
+}
+
+static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem stereo3d_display_items[] = {
+ {S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
+ "Render views for left and right eyes as two differently filtered colors in a single image "
+ "(anaglyph glasses are required)"},
+ {S3D_DISPLAY_INTERLACE, "INTERLACE", 0, "Interlace",
+ "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
+ {S3D_DISPLAY_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-Side", "Render views for left and right eyes side-by-side"},
+ {S3D_DISPLAY_TOPBOTTOM, "TOPBOTTOM", 0, "Top-Bottom", "Render views for left and right eyes one above another"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "Stereo3dFormat", NULL);
+ RNA_def_struct_sdna(srna, "Stereo3dFormat");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Stereo Output", "Settings for stereo output");
+
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "display_mode");
+ RNA_def_property_enum_items(prop, stereo3d_display_items);
+ RNA_def_property_ui_text(prop, "Stereo Mode", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_ui_text(prop, "Anaglyph Type", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_ui_text(prop, "Interlace Type", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_interlace_swap", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_INTERLACE_SWAP);
+ RNA_def_property_ui_text(prop, "Swap Left/Right", "Swap left and right stereo channels");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_sidebyside_crosseyed", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SIDEBYSIDE_CROSSEYED);
+ RNA_def_property_ui_text(prop, "Cross-Eyed", "Right eye should see left image and vice-versa");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_squeezed_frame", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SQUEEZED_FRAME);
+ RNA_def_property_ui_text(prop, "Squeezed Frame", "Combine both views in a squeezed image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+}
+
/* use for render output and image save operator,
* note: there are some cases where the members act differently when this is
* used from a scene, video formats can only be selected for render output
@@ -4070,6 +4519,8 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ rna_def_image_format_stereo3d_format(brna);
+
srna = RNA_def_struct(brna, "ImageFormatSettings", NULL);
RNA_def_struct_sdna(srna, "ImageFormatData");
RNA_def_struct_nested(brna, srna, "Scene");
@@ -4138,7 +4589,6 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_exr_codec_itemf");
RNA_def_property_ui_text(prop, "Codec", "Codec settings for OpenEXR");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
#endif
#ifdef WITH_OPENJPEG
@@ -4190,6 +4640,20 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "G", "Log conversion gamma");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ /* multiview */
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_views_format_itemf");
+ RNA_def_property_ui_text(prop, "Views Format", "Format of multiview media");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
/* color management */
prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "view_settings");
@@ -4592,6 +5056,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"resolution to 480 pixels"},
{0, NULL, 0, NULL, NULL}};
+ static EnumPropertyItem views_format_items[] = {
+ {SCE_VIEWS_FORMAT_STEREO_3D, "STEREO_3D", 0, "Stereo 3D",
+ "Single stereo camera system, adjust the stereo settings in the camera panel"},
+ {SCE_VIEWS_FORMAT_MULTIVIEW, "MULTIVIEW", 0, "Multi-View",
+ "Multi camera system, adjust the cameras individually"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+
+
rna_def_scene_ffmpeg_settings(brna);
#ifdef WITH_QUICKTIME
rna_def_scene_quicktime_settings(brna);
@@ -5274,6 +5748,32 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ /* views (stereoscopy et al) */
+ prop = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_ui_text(prop, "Render Views", "");
+ rna_def_render_views(brna, prop);
+
+ prop = RNA_def_property(srna, "stereo_views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "views", NULL);
+ RNA_def_property_collection_funcs(prop, "rna_RenderSettings_stereoViews_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_ui_text(prop, "Render Views", "");
+
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_MULTIVIEW);
+ RNA_def_property_ui_text(prop, "Multiple Views", "Use multiple views in the scene");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Setup Stereo Mode", "");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_RenderSettings_views_format_set", NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
/* engine */
prop = RNA_def_property(srna, "engine", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, engine_items);
@@ -5315,6 +5815,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+ prop = RNA_def_property(srna, "simplify_subdivision_render", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "simplify_subsurf_render");
+ RNA_def_property_ui_range(prop, 0, 6, 1, -1);
+ RNA_def_property_ui_text(prop, "Simplify Subdivision", "Global maximum subdivision level during rendering");
+ RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+
+ prop = RNA_def_property(srna, "simplify_child_particles_render", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "simplify_particles_render");
+ RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage during rendering");
+ RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+
prop = RNA_def_property(srna, "simplify_shadow_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "simplify_shadowsamples");
RNA_def_property_ui_range(prop, 1, 16, 1, -1);
@@ -5356,6 +5867,13 @@ 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, render_pass_debug_type_items);
+ RNA_def_property_ui_text(prop, "Debug Pass Type", "Type of the debug pass to use");
+#endif
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -6008,6 +6526,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
+ /* Dependency Graph */
+ prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Depsgraph");
+ RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -6024,8 +6547,8 @@ void RNA_def_scene(BlenderRNA *brna)
/* *** Animated *** */
rna_def_scene_render_data(brna);
rna_def_scene_render_layer(brna);
-
rna_def_gpu_fx(brna);
+ rna_def_scene_render_view(brna);
/* Scene API */
RNA_api_scene(srna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 36657c8a898..9d63dfe0f55 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -119,15 +119,21 @@ static void rna_Scene_update_tagged(Scene *scene)
#endif
}
-static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name)
+static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, int preview, const char *view, char *name)
{
+ const char *suffix = BKE_scene_multiview_view_suffix_get(rd, view);
+
+ /* avoid NULL pointer */
+ if (!suffix)
+ suffix = "";
+
if (BKE_imtype_is_movie(rd->im_format.imtype)) {
- BKE_movie_filepath_get(name, rd);
+ BKE_movie_filepath_get(name, rd, preview != 0, suffix);
}
else {
BKE_image_path_from_imformat(
name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame,
- &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true);
+ &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true, suffix);
}
}
@@ -287,6 +293,10 @@ 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",
+ "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 */
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index e09e0354e0b..7b30aa84cfb 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -361,49 +361,6 @@ static int rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
}
#else
-static void rna_def_palettecolor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "PaletteColor", NULL);
- RNA_def_struct_ui_text(srna, "Palette Color", "");
-
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "rgb");
- RNA_def_property_ui_text(prop, "Color", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Weight", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-}
-
-
-static void rna_def_palette(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "Palette", "ID");
- RNA_def_struct_ui_text(srna, "Palette", "");
- RNA_def_struct_ui_icon(srna, ICON_COLOR);
-
- prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "PaletteColor");
- RNA_def_property_ui_text(prop, "Palette Color", "Colors that are part of this palette");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-}
-
static void rna_def_paint_curve(BlenderRNA *brna)
{
StructRNA *srna;
@@ -505,6 +462,8 @@ static void rna_def_sculpt(BlenderRNA *brna)
"Relative Detail", "Mesh detail is relative to the brush size and detail size"},
{SCULPT_DYNTOPO_DETAIL_CONSTANT, "CONSTANT", 0,
"Constant Detail", "Mesh detail is constant in object space according to detail size"},
+ {SCULPT_DYNTOPO_DETAIL_BRUSH, "BRUSH", 0,
+ "Brush Detail", "Mesh detail is relative to brush radius"},
{0, NULL, 0, NULL, NULL}
};
@@ -562,6 +521,11 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "detail_percent", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_ui_range(prop, 0.5, 100.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_range(prop, 0.001, 10000.0);
RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
@@ -907,6 +871,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
/* brush */
@@ -918,7 +883,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 1, SHRT_MAX);
- RNA_def_property_ui_range(prop, 1, 100, 10, 3);
+ RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 10, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
@@ -962,8 +927,6 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
{
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
- rna_def_palettecolor(brna);
- rna_def_palette(brna);
rna_def_paint_curve(brna);
rna_def_paint(brna);
rna_def_sculpt(brna);
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index 5d7bb6d2d94..cbc02858f78 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -325,9 +325,11 @@ static void rna_def_sensor(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pulse False Level", "Activate FALSE level triggering (pulse mode)");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "tick_skip", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "freq");
- RNA_def_property_ui_text(prop, "Frequency", "Delay between repeated pulses(in logic tics, 0=no delay)");
+ RNA_def_property_ui_text(prop, "Skip",
+ "Number of logic ticks skipped between 2 active pulses "
+ "(0 = pulse every logic tick, 1 = skip 1 logic tick between pulses, etc.)");
RNA_def_property_range(prop, 0, 10000);
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -402,8 +404,8 @@ static void rna_def_mouse_sensor(BlenderRNA *brna)
};
static const EnumPropertyItem prop_mouse_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"},
+ {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
+ {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
{0, NULL, 0, NULL, NULL}
};
@@ -736,8 +738,8 @@ static void rna_def_ray_sensor(BlenderRNA *brna)
};
static const EnumPropertyItem prop_ray_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"},
+ {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
+ {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 8ad7d313c1e..d62509e5ab5 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -72,9 +72,9 @@ EnumPropertyItem sequence_modifier_type_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_report.h"
+#include "BKE_idprop.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "IMB_imbuf.h"
@@ -134,6 +134,14 @@ static void rna_SequenceEditor_sequences_all_begin(CollectionPropertyIterator *i
rna_iterator_listbase_begin(iter, &ed->seqbase, NULL);
}
+static void rna_SequenceEditor_update_cache(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ Editing *ed = scene->ed;
+
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+}
+
+
static void rna_SequenceEditor_sequences_all_next(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -177,6 +185,11 @@ static void rna_SequenceEditor_elements_begin(CollectionPropertyIterator *iter,
rna_SequenceEditor_elements_length(ptr), 0, NULL);
}
+static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Sequence_update(bmain, scene, ptr);
+}
+
static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -476,7 +489,7 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value)
/* fix all the animation data which may link to this */
/* don't rename everywhere because these are per scene */
- /* BKE_all_animdata_fix_paths_rename(NULL, "sequence_editor.sequences_all", oldname, seq->name + 2); */
+ /* BKE_animdata_fix_paths_rename_all(NULL, "sequence_editor.sequences_all", oldname, seq->name + 2); */
adt = BKE_animdata_from_id(&scene->id);
if (adt)
BKE_animdata_fix_paths_rename(&scene->id, adt, NULL, "sequence_editor.sequences_all", oldname, seq->name + 2, 0, 0, 1);
@@ -556,6 +569,18 @@ static char *rna_Sequence_path(PointerRNA *ptr)
}
}
+static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
+{
+ Sequence *seq = ptr->data;
+
+ if (create && !seq->prop) {
+ IDPropertyTemplate val = {0};
+ seq->prop = IDP_New(IDP_GROUP, &val, "Sequence ID properties");
+ }
+
+ return seq->prop;
+}
+
static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -577,8 +602,8 @@ static void rna_Sequence_filepath_set(PointerRNA *ptr, const char *value)
PointerRNA id_ptr;
RNA_id_pointer_create((ID *)seq->sound, &id_ptr);
RNA_string_set(&id_ptr, "filepath", value);
- sound_load(G.main, seq->sound);
- sound_update_scene_sound(seq->scene_sound, seq->sound);
+ BKE_sound_load(G.main, seq->sound);
+ BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
}
BLI_split_dirfile(value, seq->strip->dir, seq->strip->stripdata->name, sizeof(seq->strip->dir),
@@ -633,7 +658,7 @@ static void rna_Sequence_volume_set(PointerRNA *ptr, float value)
seq->volume = value;
if (seq->scene_sound)
- sound_set_scene_sound_volume(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_volume(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
}
static void rna_Sequence_pitch_set(PointerRNA *ptr, float value)
@@ -642,7 +667,7 @@ static void rna_Sequence_pitch_set(PointerRNA *ptr, float value)
seq->pitch = value;
if (seq->scene_sound)
- sound_set_scene_sound_pitch(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_pitch(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
}
static void rna_Sequence_pan_set(PointerRNA *ptr, float value)
@@ -651,7 +676,7 @@ static void rna_Sequence_pan_set(PointerRNA *ptr, float value)
seq->pan = value;
if (seq->scene_sound)
- sound_set_scene_sound_pan(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_pan(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}
@@ -783,7 +808,7 @@ static int colbalance_seq_cmp_cb(Sequence *seq, void *arg_pt)
return 1;
}
-static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb, SequenceModifierData **smd_r)
+static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb, SequenceModifierData **r_smd)
{
SequenceSearchData data;
@@ -794,7 +819,7 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb
/* irritating we need to search for our sequence! */
BKE_sequencer_base_recursive_apply(&ed->seqbase, colbalance_seq_cmp_cb, &data);
- *smd_r = data.smd;
+ *r_smd = data.smd;
return data.seq;
}
@@ -1222,6 +1247,15 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "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);
+ RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_DIR);
+ RNA_def_property_ui_text(prop, "Proxy Custom Directory", "Use a custom directory to store data");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+ prop = RNA_def_property(srna, "use_proxy_custom_file", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_FILE);
+ RNA_def_property_ui_text(prop, "Proxy Custom File", "Use a custom file to read proxy data from");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
static void rna_def_color_balance(BlenderRNA *brna)
@@ -1380,6 +1414,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Sequence", "Sequence strip in the sequence editor");
RNA_def_struct_refine_func(srna, "rna_Sequence_refine");
RNA_def_struct_path_func(srna, "rna_Sequence_path");
+ RNA_def_struct_idprops_func(srna, "rna_Sequence_idprops");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_Sequence_name_get", "rna_Sequence_name_length", "rna_Sequence_name_set");
@@ -1559,7 +1594,12 @@ static void rna_def_editor(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
+ static const EnumPropertyItem editing_storage_items[] = {
+ {0, "PER_STRIP", 0, "Per Strip", "Store proxies using per strip settings"},
+ {SEQ_EDIT_PROXY_DIR_STORAGE, "PROJECT", 0, "Project", "Store proxies using project directory"},
+ {0, NULL, 0, NULL, NULL}
+ };
srna = RNA_def_struct(brna, "SequenceEditor", NULL);
RNA_def_struct_ui_text(srna, "Sequence Editor", "Sequence editing data for a Scene datablock");
RNA_def_struct_ui_icon(srna, ICON_SEQUENCE);
@@ -1607,6 +1647,16 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, "rna_SequenceEditor_overlay_frame_get",
"rna_SequenceEditor_overlay_frame_set", NULL);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "proxy_storage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, editing_storage_items);
+ RNA_def_property_ui_text(prop, "Proxy Storage", "How to store proxies for this project");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
+
+ prop = RNA_def_property(srna, "proxy_dir", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_sdna(prop, NULL, "proxy_dir");
+ RNA_def_property_ui_text(prop, "Proxy Directory", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -1702,16 +1752,6 @@ static void rna_def_proxy(StructRNA *srna)
prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->proxy");
RNA_def_property_ui_text(prop, "Proxy", "");
-
- prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY_CUSTOM_DIR);
- RNA_def_property_ui_text(prop, "Proxy Custom Directory", "Use a custom directory to store data");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
-
- prop = RNA_def_property(srna, "use_proxy_custom_file", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY_CUSTOM_FILE);
- RNA_def_property_ui_text(prop, "Proxy Custom File", "Use a custom file to read proxy data from");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
static void rna_def_input(StructRNA *srna)
@@ -1798,6 +1838,24 @@ static void rna_def_image(BlenderRNA *brna)
"rna_SequenceEditor_elements_length", NULL, NULL, NULL);
RNA_api_sequence_elements(brna, prop);
+ /* multiview */
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
@@ -1889,6 +1947,24 @@ static void rna_def_movie(BlenderRNA *brna)
"rna_Sequence_filepath_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
+ /* multiview */
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load movie views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 351a15c0171..5e9866fa73e 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -42,8 +42,6 @@
//#include "DNA_anim_types.h"
#include "DNA_image_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_sequence_types.h"
#include "DNA_mask_types.h"
#include "DNA_sound_types.h"
@@ -158,7 +156,7 @@ static Sequence *rna_Sequences_new_scene(ID *id, Editing *ed,
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SCENE, NULL);
seq->scene = sce_seq;
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
- seq->scene_sound = sound_scene_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
id_us_plus((ID *)sce_seq);
BKE_sequence_calc_disp(scene, seq);
@@ -198,6 +196,7 @@ static Sequence *rna_Sequences_new_movie(ID *id, Editing *ed, ReportList *report
{
Scene *scene = (Scene *)id;
Sequence *seq;
+ StripAnim *sanim;
struct anim *an = openanim(file, IB_rect, 0, NULL);
@@ -207,7 +206,11 @@ static Sequence *rna_Sequences_new_movie(ID *id, Editing *ed, ReportList *report
}
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
- seq->anim = an;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = an;
+
seq->anim_preseek = IMB_anim_get_preseek(an);
seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
@@ -225,18 +228,19 @@ static Sequence *rna_Sequences_new_sound(ID *id, Editing *ed, Main *bmain, Repor
Scene *scene = (Scene *)id;
Sequence *seq;
- bSound *sound = sound_new_file(bmain, file);
+ bSound *sound = BKE_sound_new_file(bmain, file);
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
+ BKE_libblock_free(bmain, sound);
BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file");
return NULL;
}
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->name);
seq->sound = sound;
- seq->len = ceil((double)sound_get_length(sound) * FPS);
+ seq->len = ceil((double)BKE_sound_get_length(sound) * FPS);
- seq->scene_sound = sound_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
+ seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 55262a98b2e..539f3c192be 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -165,6 +165,31 @@ static int rna_SmokeModifier_color_grid_get_length(PointerRNA *ptr, int length[R
return length[0];
}
+static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ float *vx = NULL;
+ float *vy = NULL;
+ float *vz = NULL;
+ int size = 0;
+
+ /* Velocity data is always low-resolution. */
+ if (sds->fluid) {
+ size = 3 * sds->res[0] * sds->res[1] * sds->res[2];
+ vx = smoke_get_velocity_x(sds->fluid);
+ vy = smoke_get_velocity_y(sds->fluid);
+ vz = smoke_get_velocity_z(sds->fluid);
+ }
+
+ length[0] = (vx && vy && vz) ? size : 0;
+#else
+ (void)ptr;
+ length[0] = 0;
+#endif
+ return length[0];
+}
+
static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
@@ -184,8 +209,34 @@ static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
- (void)ptr;
- (void)values;
+ UNUSED_VARS(ptr, values);
+#endif
+}
+
+static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values)
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length);
+ float *vx, *vy, *vz;
+ int i;
+
+ BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+ vx = smoke_get_velocity_x(sds->fluid);
+ vy = smoke_get_velocity_y(sds->fluid);
+ vz = smoke_get_velocity_z(sds->fluid);
+
+ for (i = 0; i < size; i += 3) {
+ *(values++) = *(vx++);
+ *(values++) = *(vy++);
+ *(values++) = *(vz++);
+ }
+
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+#else
+ UNUSED_VARS(ptr, values);
#endif
}
@@ -211,8 +262,7 @@ static void rna_SmokeModifier_color_grid_get(PointerRNA *ptr, float *values)
BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
- (void)ptr;
- memset(values, 0, 4 * sizeof(float));
+ UNUSED_VARS(ptr, values);
#endif
}
@@ -238,8 +288,7 @@ static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
BLI_rw_mutex_unlock(sds->fluid_mutex);
#else
- (void)ptr;
- (void)values;
+ UNUSED_VARS(ptr, values);
#endif
}
@@ -453,6 +502,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_grid_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid");
+ prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_velocity_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_SmokeModifier_velocity_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid");
+
prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 32);
RNA_def_property_flag(prop, PROP_DYNAMIC);
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 4b745c60b5b..25b3475c423 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -42,7 +42,7 @@
static void rna_Sound_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- sound_load(bmain, (bSound *)ptr->data);
+ BKE_sound_load(bmain, (bSound *)ptr->data);
}
static int rna_Sound_caching_get(PointerRNA *ptr)
@@ -55,9 +55,9 @@ static void rna_Sound_caching_set(PointerRNA *ptr, const int value)
{
bSound *sound = (bSound *)(ptr->data);
if (value)
- sound_cache(sound);
+ BKE_sound_cache(sound);
else
- sound_delete_cache(sound);
+ BKE_sound_delete_cache(sound);
}
static void rna_Sound_caching_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 9e7d70ab3b2..20a6bd67dea 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -31,10 +31,10 @@
#include "BLF_translation.h"
+#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_screen.h"
#include "DNA_action_types.h"
#include "DNA_key_types.h"
@@ -57,8 +57,6 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
-#include "ED_fileselect.h"
-
#include "RNA_enum_types.h"
@@ -90,6 +88,41 @@ EnumPropertyItem space_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#define V3D_S3D_CAMERA_LEFT {STEREO_LEFT_ID, "LEFT", ICON_RESTRICT_RENDER_OFF, "Left", ""},
+#define V3D_S3D_CAMERA_RIGHT {STEREO_RIGHT_ID, "RIGHT", ICON_RESTRICT_RENDER_OFF, "Right", ""},
+#define V3D_S3D_CAMERA_S3D {STEREO_3D_ID, "S3D", ICON_CAMERA_STEREO, "3D", ""},
+#ifdef RNA_RUNTIME
+#define V3D_S3D_CAMERA_VIEWS {STEREO_MONO_ID, "MONO", ICON_RESTRICT_RENDER_OFF, "Views", ""},
+#endif
+
+static EnumPropertyItem stereo3d_camera_items[] = {
+ V3D_S3D_CAMERA_LEFT
+ V3D_S3D_CAMERA_RIGHT
+ V3D_S3D_CAMERA_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifdef RNA_RUNTIME
+static EnumPropertyItem multiview_camera_items[] = {
+ V3D_S3D_CAMERA_VIEWS
+ V3D_S3D_CAMERA_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
+#undef V3D_S3D_CAMERA_LEFT
+#undef V3D_S3D_CAMERA_RIGHT
+#undef V3D_S3D_CAMERA_S3D
+#undef V3D_S3D_CAMERA_VIEWS
+
+#ifndef RNA_RUNTIME
+static EnumPropertyItem stereo3d_eye_items[] = {
+ {STEREO_LEFT_ID, "LEFT_EYE", ICON_NONE, "Left Eye"},
+ {STEREO_RIGHT_ID, "RIGHT_EYE", ICON_NONE, "Right Eye"},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
static EnumPropertyItem pivot_items_full[] = {
{V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
@@ -189,7 +222,6 @@ static EnumPropertyItem buttons_texture_context_items[] = {
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
-#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -201,6 +233,7 @@ static EnumPropertyItem buttons_texture_context_items[] = {
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_nla.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -413,8 +446,8 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
/* seek for layact */
bit = 0;
while (bit < 32) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
bit++;
@@ -493,8 +526,11 @@ static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(sce
{
View3D *v3d = (View3D *)(ptr->data);
- if (v3d->matcap_icon == 0)
+ if (v3d->matcap_icon < ICON_MATCAP_01 ||
+ v3d->matcap_icon > ICON_MATCAP_24)
+ {
v3d->matcap_icon = ICON_MATCAP_01;
+ }
}
static void rna_SpaceView3D_pivot_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -656,6 +692,17 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
return item;
}
+static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ Scene *scene = ((bScreen *)ptr->id.data)->scene;
+
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return multiview_camera_items;
+ else
+ return stereo3d_camera_items;
+}
+
/* Space Image Editor */
static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr)
@@ -668,6 +715,38 @@ static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerR
ED_space_image_paint_update(bmain->wm.first, scene->toolsettings);
}
+
+static void rna_SpaceImageEditor_show_stereo_set(PointerRNA *ptr, int value)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+
+ if (value)
+ sima->iuser.flag |= IMA_SHOW_STEREO;
+ else
+ sima->iuser.flag &= ~IMA_SHOW_STEREO;
+}
+
+static int rna_SpaceImageEditor_show_stereo_get(PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+ return (sima->iuser.flag & IMA_SHOW_STEREO) != 0;
+}
+
+static void rna_SpaceImageEditor_show_stereo_update(Main *UNUSED(bmain), Scene *UNUSED(unused), PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+ Image *ima = sima->image;
+
+ if (ima) {
+ if (ima->rr) {
+ BKE_image_multilayer_index(ima->rr, &sima->iuser);
+ }
+ else {
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+ }
+}
+
static int rna_SpaceImageEditor_show_render_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
@@ -795,6 +874,24 @@ static void rna_SpaceImageEditor_cursor_location_set(PointerRNA *ptr, const floa
}
}
+static void rna_SpaceImageEditor_image_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)ptr->data;
+ Image *ima = sima->image;
+
+ /* make sure all the iuser settings are valid for the sima image */
+ if (ima) {
+ if (ima->rr) {
+ if (BKE_image_multilayer_index(sima->image->rr, &sima->iuser) == NULL) {
+ BKE_image_init_imageuser(sima->image, &sima->iuser);
+ }
+ }
+ else {
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+ }
+}
+
static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
@@ -816,6 +913,8 @@ static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), P
{V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
{V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
{V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
+ {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ "Individual Origins", "Pivot around each object's own origin"},
{0, NULL, 0, NULL, NULL}
};
@@ -1114,24 +1213,60 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *UNUSED(bmain), Scene *s
if (saction->mode == SACTCONT_ACTION) {
/* TODO: context selector could help decide this with more control? */
- adt = BKE_id_add_animdata(&obact->id); /* this only adds if non-existent */
+ adt = BKE_animdata_add_id(&obact->id); /* this only adds if non-existent */
}
else if (saction->mode == SACTCONT_SHAPEKEY) {
Key *key = BKE_key_from_object(obact);
if (key)
- adt = BKE_id_add_animdata(&key->id); /* this only adds if non-existent */
+ 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) {
- /* fix id-count of action we're replacing */
- id_us_min(&adt->action->id);
-
- /* assign new action, and adjust the usercounts accordingly */
- adt->action = saction->action;
- id_us_plus(&adt->action->id);
+ /* Don't do anything if old and new actions are the same... */
+ 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
+ * 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);
+ }
+ else {
+ /* Handle old action... */
+ 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.
+ *
+ * EXCEPTION:
+ * This callback runs when unlinking actions. In that case, we don't want to
+ * stash the action, as the user is signalling that they want to detach it.
+ * This can be reviewed again later, but it could get annoying if we keep these instead.
+ */
+ if ((adt->action->id.us <= 0) && (saction->action != NULL)) {
+ /* XXX: Things here get dodgy if this action is only partially completed,
+ * and the user then uses the browse menu to get back to this action,
+ * assigning it as the active action (i.e. the stash strip gets out of sync)
+ */
+ 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 */
+ /* Force update of animdata */
adt->recalc |= ADT_RECALC_ANIM;
}
@@ -1211,6 +1346,19 @@ static void rna_BackgroundImage_opacity_set(PointerRNA *ptr, float value)
bgpic->blend = 1.0f - value;
}
+/* radius internally (expose as a distance value) */
+static float rna_BackgroundImage_size_get(PointerRNA *ptr)
+{
+ BGpic *bgpic = ptr->data;
+ return bgpic->size * 2.0f;
+}
+
+static void rna_BackgroundImage_size_set(PointerRNA *ptr, float value)
+{
+ BGpic *bgpic = ptr->data;
+ bgpic->size = value * 0.5f;
+}
+
static BGpic *rna_BackgroundImage_new(View3D *v3d)
{
BGpic *bgpic = ED_view3D_background_image_new(v3d);
@@ -1780,6 +1928,11 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_METADATA);
+ RNA_def_property_ui_text(prop, "Show Metadata", "Draw metadata properties of the image");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAW_TEXPAINT);
RNA_def_property_ui_text(prop, "Draw Texture Paint UVs", "Draw overlay of texture paint uv layer");
@@ -1966,15 +2119,16 @@ static void rna_def_background_image(BlenderRNA *brna)
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_NONE);
+ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_ui_text(prop, "Size", "Scaling factor for the background image");
+ RNA_def_property_float_funcs(prop, "rna_BackgroundImage_size_get", "rna_BackgroundImage_size_set", NULL);
+ RNA_def_property_ui_text(prop, "Size", "Size of the background image (ortho view only)");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rotation");
- RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image");
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image (ortho view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
@@ -2469,6 +2623,48 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ /* Stereo Settings */
+ prop = RNA_def_property(srna, "stereo_3d_eye", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "multiview_eye");
+ RNA_def_property_enum_items(prop, stereo3d_eye_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceView3D_stereo3d_camera_itemf");
+ RNA_def_property_ui_text(prop, "Stereo Eye", "Current stereo eye being drawn");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "stereo_3d_camera", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "stereo3d_camera");
+ RNA_def_property_enum_items(prop, stereo3d_camera_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceView3D_stereo3d_camera_itemf");
+ RNA_def_property_ui_text(prop, "Camera", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_cameras", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPCAMERAS);
+ RNA_def_property_ui_text(prop, "Cameras", "Show the left and right cameras");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_convergence_plane", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPPLANE);
+ RNA_def_property_ui_text(prop, "Plane", "Show the stereo 3d convergence plane");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_convergence_plane_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "stereo3d_convergence_alpha");
+ RNA_def_property_ui_text(prop, "Plane Alpha", "Opacity (alpha) of the convergence plane");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPVOLUME);
+ RNA_def_property_ui_text(prop, "Volume", "Show the stereo 3d frustum volume");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_volume_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "stereo3d_volume_alpha");
+ RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* *** Animated *** */
+ RNA_define_animate_sdna(true);
/* region */
srna = RNA_def_struct(brna, "RegionView3D", NULL);
@@ -2642,7 +2838,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceImageEditor_image_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Image", "Image displayed and edited in this space");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_GEOM | ND_DATA, NULL); /* is handled in image editor too */
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_SpaceImageEditor_image_update"); /* is handled in image editor too */
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2694,6 +2890,12 @@ static void rna_def_space_image(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_IMAGE, NULL);
+ prop = RNA_def_property(srna, "show_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_SpaceImageEditor_show_stereo_get", "rna_SpaceImageEditor_show_stereo_set");
+ RNA_def_property_ui_text(prop, "Show Stereo", "Display the image in Stereo 3D");
+ RNA_def_property_ui_icon(prop, ICON_CAMERA_STEREO, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_show_stereo_update");
+
/* uv */
prop = RNA_def_property(srna, "uv_editor", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2870,6 +3072,11 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Center-Cut Safe Areas", "Show safe areas to fit content in a different aspect ratio");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+ prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_METADATA);
+ RNA_def_property_ui_text(prop, "Show Metadata", "Show metadata of first visible strip");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
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");
@@ -3003,14 +3210,15 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "top", PROP_INT, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_sdna(prop, NULL, "top");
+ RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop, "Top Line", "Top line visible");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "visible_lines", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_sdna(prop, NULL, "viewlines");
- RNA_def_property_ui_text(prop, "Top Line", "Amount of lines that can be visible in current editor");
+ RNA_def_property_ui_text(prop, "Visible Lines", "Amount of lines that can be visible in current editor");
/* functionality options */
prop = RNA_def_property(srna, "use_overwrite", PROP_BOOLEAN, PROP_NONE);
@@ -3494,6 +3702,14 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem thumbnail_size_items[] = {
+ {32, "TINY", 0, "Tiny", ""},
+ {64, "SMALL", 0, "Small", ""},
+ {128, "NORMAL", 0, "Normal", ""},
+ {256, "LARGE", 0, "Large", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "FileSelectParams", NULL);
RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters");
@@ -3598,6 +3814,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name Filter", "Filter by name, supports '*' wildcard");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+
+ prop = RNA_def_property(srna, "thumbnail_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "thumbnail_size");
+ RNA_def_property_enum_items(prop, thumbnail_size_items);
+ RNA_def_property_ui_text(prop, "Thumbnails Size", "Change the size of the thumbnails");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
static void rna_def_filemenu_entry(BlenderRNA *brna)
@@ -4187,6 +4409,11 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SC_HIDE_DISABLED);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
+ prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_METADATA);
+ RNA_def_property_ui_text(prop, "Show Metadata", "Show metadata of clip");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
+
/* scopes */
prop = RNA_def_property(srna, "scopes", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "scopes");
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index c1882e7767d..726744782ed 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -181,7 +181,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
TexMapping *texmap = ptr->data;
- init_tex_mapping(texmap);
+ BKE_texture_mapping_init(texmap);
rna_Texture_update(bmain, scene, ptr);
}
@@ -222,7 +222,7 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value)
{
Tex *tex = (Tex *)ptr->data;
- tex_set_type(tex, value);
+ BKE_texture_type_set(tex, value);
}
void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -445,7 +445,7 @@ static void rna_Envmap_update_generic(Main *bmain, Scene *scene, PointerRNA *ptr
Tex *tex = ptr->id.data;
if (tex->env) {
ED_preview_kill_jobs(bmain->wm.first, bmain);
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
}
rna_Texture_update(bmain, scene, ptr);
}
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index acf8333d6dc..a27ba6ea06d 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -60,7 +60,7 @@ static void clear_envmap(struct EnvMap *env, bContext *C)
Main *bmain = CTX_data_main(C);
Tex *tex;
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->env == env) {
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index fea8b630af6..d75966f6599 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -231,11 +231,15 @@ static void rna_uiItemL(uiLayout *layout, const char *name, const char *text_ctx
}
static void rna_uiItemM(uiLayout *layout, bContext *C, const char *menuname, const char *name, const char *text_ctxt,
- int translate, int icon)
+ int translate, int icon, int icon_value)
{
/* Get translated name (label). */
name = rna_translate_ui_text(name, text_ctxt, NULL, NULL, translate);
+ if (icon_value && !icon) {
+ icon = icon_value;
+ }
+
uiItemM(layout, C, menuname, name, icon);
}
@@ -525,9 +529,7 @@ void RNA_api_ui_layout(StructRNA *srna)
"The index of this button, when set a single member of an array can be accessed, "
"when set to -1 all array members are used", -2, INT_MAX); /* RNA_NO_INDEX == -1 */
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 "
- "(use it e.g. with custom material icons returned by icon()...)");
+ RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
func = RNA_def_function(srna, "props_enum", "uiItemsEnumR");
api_ui_item_rna_common(func);
@@ -554,9 +556,7 @@ void RNA_api_ui_layout(StructRNA *srna)
api_ui_item_op_common(func);
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 "
- "(use it e.g. with custom material icons returned by icon()...)");
+ 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);
@@ -621,15 +621,15 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
api_ui_item_common(func);
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 "
- "(use it e.g. with custom material icons returned by icon()...)");
+ RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
func = RNA_def_function(srna, "menu", "rna_uiItemM");
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);
+ 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");
func = RNA_def_function(srna, "separator", "uiItemS");
RNA_def_function_ui_description(func, "Item. Inserts empty space into the layout between items");
@@ -719,11 +719,12 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A color ramp widget");
api_ui_item_rna_common(func);
RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail");
-
+
func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView");
RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews");
api_ui_item_rna_common(func);
-
+ RNA_def_boolean(func, "show_labels", false, "", "Show enum label in preview buttons");
+
func = RNA_def_function(srna, "template_histogram", "uiTemplateHistogram");
RNA_def_function_ui_description(func, "Item. A histogramm widget to analyze imaga data");
api_ui_item_rna_common(func);
@@ -772,6 +773,7 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "image_user", "ImageUser", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
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");
@@ -779,6 +781,16 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
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);
+
+ 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);
+
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");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index e60af76851e..9123a0682e6 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -87,7 +87,6 @@ EnumPropertyItem navigation_mode_items[] = {
#include "DNA_screen_types.h"
#include "BKE_blender.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -105,8 +104,6 @@ EnumPropertyItem navigation_mode_items[] = {
#include "CCL_api.h"
-#include "BKE_addon.h"
-
#ifdef WITH_SDL_DYNLOAD
# include "sdlew.h"
#endif
@@ -331,7 +328,7 @@ static PointerRNA rna_UserDef_system_get(PointerRNA *ptr)
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- sound_init(bmain);
+ BKE_sound_init(bmain);
}
static void rna_Userdef_memcache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -548,7 +545,7 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi
#endif
#ifdef WITH_JACK
- if (sound_is_jack_supported()) {
+ if (BKE_sound_is_jack_supported()) {
RNA_enum_item_add(&item, &totitem, &audio_device_items[index]);
}
index++;
@@ -2386,6 +2383,18 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "metadatabg", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatabg");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatatext", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatatext");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Text", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
rna_def_userdef_theme_spaces_curves(srna, false, false, false, true);
rna_def_userdef_theme_spaces_paint_curves(srna);
@@ -2488,6 +2497,18 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Preview Background", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatabg", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatabg");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatatext", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatatext");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Text", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
@@ -3239,7 +3260,14 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Direct conversion of frame numbers to seconds"},
{0, NULL, 0, NULL, NULL}
};
-
+
+ static EnumPropertyItem zoom_frame_modes[] = {
+ {ZOOM_FRAME_MODE_KEEP_RANGE, "KEEP_RANGE", 0, "Keep Range", ""},
+ {ZOOM_FRAME_MODE_SECONDS, "SECONDS", 0, "Seconds", ""},
+ {ZOOM_FRAME_MODE_KEYFRAMES, "KEYFRAMES", 0, "Keyframes", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -3428,8 +3456,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Smooth View", "Time to animate the view in milliseconds, zero to disable");
- prop = RNA_def_property(srna, "rotation_angle", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "pad_rot_angle");
+ prop = RNA_def_property(srna, "rotation_angle", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pad_rot_angle");
RNA_def_property_range(prop, 0, 90);
RNA_def_property_ui_text(prop, "Rotation Angle", "Rotation step for numerical pad keys (2 4 6 8)");
@@ -3481,6 +3509,22 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "TimeCode Style",
"Format of Time Codes displayed when not displaying timing in terms of frames");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "view_frame_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, zoom_frame_modes);
+ RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
+ RNA_def_property_ui_text(prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
+
+ prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 500);
+ RNA_def_property_ui_text(prop, "Zoom Keyframes",
+ "Keyframes around cursor that we zoom around");
+
+ prop = RNA_def_property(srna, "view_frame_seconds", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_text(prop, "Zoom Seconds",
+ "Seconds around cursor that we zoom around");
+
}
static void rna_def_userdef_edit(BlenderRNA *brna)
@@ -3601,7 +3645,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "New Interpolation Type",
"Interpolation mode used for first keyframe on newly added F-Curves "
"(subsequent keyframes take interpolation from preceding keyframe)");
-
+
prop = RNA_def_property(srna, "keyframe_new_handle_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, keyframe_handle_type_items);
RNA_def_property_enum_sdna(prop, NULL, "keyhandles_new");
@@ -3648,7 +3692,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
- prop = RNA_def_property(srna, "grease_pencil_default_color", PROP_FLOAT, PROP_COLOR);
+ prop = RNA_def_property(srna, "grease_pencil_default_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "gpencil_new_layer_col");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Grease Pencil Default Color", "Color of new Grease Pencil layers");
@@ -4124,8 +4168,8 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP);
RNA_def_property_ui_text(prop, "Region Overlap",
"Draw tool/property regions over the main region, when using Triple Buffer");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
+
#ifdef WITH_CYCLES
prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 6119bc968e6..4446f5d9a2b 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -414,7 +414,7 @@ static EnumPropertyItem operator_flag_items[] = {
{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
- {OPTYPE_GRAB_POINTER, "GRAB_POINTER", 0, "Grab Pointer",
+ {OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
"Use so the operator grabs the mouse focus, enables wrapping when continuous grab "
"is enabled"},
{OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"},
@@ -511,6 +511,11 @@ static int rna_Operator_has_reports_get(PointerRNA *ptr)
return (op->reports && op->reports->list.first);
}
+static PointerRNA rna_Operator_options_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_OperatorOptions, ptr->data);
+}
+
static PointerRNA rna_Operator_properties_get(PointerRNA *ptr)
{
wmOperator *op = (wmOperator *)ptr->data;
@@ -790,6 +795,29 @@ static void rna_KeyMapItem_any_set(PointerRNA *ptr, int value)
}
}
+static int rna_KeyMapItem_shift_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->shift != 0;
+}
+
+static int rna_KeyMapItem_ctrl_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->ctrl != 0;
+}
+
+static int rna_KeyMapItem_alt_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->alt != 0;
+}
+
+static int rna_KeyMapItem_oskey_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->oskey != 0;
+}
static PointerRNA rna_WindowManager_active_keyconfig_get(PointerRNA *ptr)
{
@@ -1367,6 +1395,33 @@ static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
#else /* RNA_RUNTIME */
+/**
+ * expose ``Operator.options`` as its own type so we can control each flags use (some are read-only).
+ */
+static void rna_def_operator_options_runtime(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OperatorOptions", NULL);
+ RNA_def_struct_ui_text(srna, "Operator Options", "Runtime options");
+ RNA_def_struct_sdna(srna, "wmOperator");
+
+ prop = RNA_def_property(srna, "is_grab_cursor", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_GRAB_CURSOR);
+ RNA_def_property_ui_text(prop, "Grab Cursor", "True when the cursor is grabbed");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "is_invoke", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_INVOKE);
+ RNA_def_property_ui_text(prop, "Invoke", "True when invoked (even if only the execute callbacks available)");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "use_cursor_region", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_CURSOR_REGION);
+ RNA_def_property_ui_text(prop, "Focus Region", "Enable to use the region under the cursor for modal execution");
+}
+
static void rna_def_operator(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1401,6 +1456,12 @@ static void rna_def_operator(BlenderRNA *brna)
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "UILayout");
+ prop = RNA_def_property(srna, "options", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "OperatorOptions");
+ RNA_def_property_pointer_funcs(prop, "rna_Operator_options_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Options", "Runtime options");
+
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
@@ -1440,6 +1501,11 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+ prop = RNA_def_property(srna, "macros", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "macro", NULL);
+ RNA_def_property_struct_type(prop, "Macro");
+ RNA_def_property_ui_text(prop, "Macros", "");
+
RNA_api_operator(srna);
srna = RNA_def_struct(brna, "OperatorProperties", NULL);
@@ -1748,6 +1814,37 @@ static void rna_def_piemenu(BlenderRNA *brna)
RNA_define_verify_sdna(1); /* not in sdna */
}
+static void rna_def_window_stereo3d(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Stereo3dDisplay", NULL);
+ RNA_def_struct_sdna(srna, "Stereo3dFormat");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Stereo 3D Display", "Settings for stereo 3D display");
+
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_display_items);
+ RNA_def_property_ui_text(prop, "Display Mode", "");
+
+ prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_ui_text(prop, "Anaglyph Type", "");
+
+ prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_ui_text(prop, "Interlace Type", "");
+
+ prop = RNA_def_property(srna, "use_interlace_swap", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_INTERLACE_SWAP);
+ RNA_def_property_ui_text(prop, "Swap Left/Right", "Swap left and right stereo channels");
+
+ prop = RNA_def_property(srna, "use_sidebyside_crosseyed", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SIDEBYSIDE_CROSSEYED);
+ RNA_def_property_ui_text(prop, "Cross-Eyed", "Right eye should see left image and vice-versa");
+}
+
static void rna_def_window(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1757,6 +1854,8 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Window", "Open window");
RNA_def_struct_sdna(srna, "wmWindow");
+ rna_def_window_stereo3d(brna);
+
prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "Screen");
@@ -1786,6 +1885,12 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Height", "Window height");
+ prop = RNA_def_property(srna, "stereo_3d_display", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dDisplay");
+ RNA_def_property_ui_text(prop, "Stereo 3D Display", "Settings for stereo 3d display");
+
RNA_api_window(srna);
}
@@ -2034,6 +2139,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shift", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_shift_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "shift"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Shift", "Shift key pressed");
@@ -2041,6 +2147,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_ctrl_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "ctrl"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed");
@@ -2048,6 +2155,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "alt", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "alt", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_alt_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "alt"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Alt", "Alt key pressed");
@@ -2055,6 +2163,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "oskey", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "oskey", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_oskey_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "oskey"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed");
@@ -2103,6 +2212,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
void RNA_def_wm(BlenderRNA *brna)
{
rna_def_operator(brna);
+ rna_def_operator_options_runtime(brna);
rna_def_operator_utils(brna);
rna_def_operator_filelist_element(brna);
rna_def_macro_operator(brna);
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 721cbaf21c7..3f55ad9c668 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -92,6 +92,7 @@ static void rna_World_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
WM_main_add_notifier(NC_WORLD | ND_WORLD, wo);
}
+#if 0
static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
World *wo = ptr->id.data;
@@ -99,6 +100,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
DAG_id_tag_update(&wo->id, 0);
WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, wo);
}
+#endif
/* so camera mist limits redraw */
static void rna_World_draw_mist_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -403,13 +405,13 @@ static void rna_def_world_mist(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_MIST);
RNA_def_property_ui_text(prop, "Use Mist", "Occlude objects with the environment color as they are further away");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "misi");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Minimum", "Overall minimum intensity of the mist effect");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "miststa");
@@ -435,7 +437,7 @@ static void rna_def_world_mist(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mistype");
RNA_def_property_enum_items(prop, falloff_items);
RNA_def_property_ui_text(prop, "Falloff", "Type of transition used to fade mist");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
}
void RNA_def_world(BlenderRNA *brna)
@@ -460,8 +462,7 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon");
/* RNA_def_property_update(prop, 0, "rna_World_update"); */
/* render-only uses this */
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
-
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "zenr");
@@ -473,7 +474,7 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "ambr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
/* exp, range */
prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 57e927fffed..fde0c773ef0 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenkernel
../blenlib
../blenfont
+ ../depsgraph
../makesdna
../makesrna
../bmesh
@@ -51,6 +52,7 @@ set(SRC
intern/MOD_cast.c
intern/MOD_cloth.c
intern/MOD_collision.c
+ intern/MOD_correctivesmooth.c
intern/MOD_curve.c
intern/MOD_datatransfer.c
intern/MOD_decimate.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 66e613be68a..a5d96759952 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -83,6 +83,7 @@ extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
+extern ModifierTypeInfo modifierType_CorrectiveSmooth;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index b4c8299250e..a7d17609ab7 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -40,6 +40,7 @@ incs = [
'../include',
'../blenlib',
'../blenfont',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../blenkernel',
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 52a47c3e041..9ce31cebb66 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -115,6 +115,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object != NULL) {
+ DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -208,6 +220,7 @@ ModifierTypeInfo modifierType_Armature = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 409d862addb..efb77f73ec9 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -135,6 +135,28 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ if (amd->start_cap != NULL) {
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ }
+ if (amd->end_cap != NULL) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ }
+ if (amd->curve_ob) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
+ DEG_add_special_eval_flag(scene->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, "Hook Modifier Offset");
+ }
+}
+
static float vertarray_size(const MVert *mvert, int numVerts, int axis)
{
int i;
@@ -364,22 +386,22 @@ static void dm_merge_transform(
/* set origindex */
index_orig = result->getVertDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
}
index_orig = result->getEdgeDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
}
index_orig = result->getPolyDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
}
index_orig = result->getLoopDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
}
}
@@ -501,7 +523,7 @@ static DerivedMesh *arrayModifier_doArray(
if (dist > eps) {
/* this gives length = first copy start to last copy end
* add a tiny offset for floating point rounding errors */
- count = (length + eps) / dist;
+ count = (length + eps) / dist + 1;
}
else {
/* if the offset has no translation, just make one copy */
@@ -525,7 +547,7 @@ static DerivedMesh *arrayModifier_doArray(
if (use_merge) {
/* Will need full_doubles_map for handling merge */
full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map");
- fill_vn_i(full_doubles_map, result_nverts, -1);
+ copy_vn_i(full_doubles_map, result_nverts, -1);
}
/* copy customdata to original geometry */
@@ -771,6 +793,7 @@ ModifierTypeInfo modifierType_Array = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 1dca18dce37..c2b5a29939f 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -213,6 +213,7 @@ ModifierTypeInfo modifierType_Bevel = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index ee3bc7140a8..eb54a3c4e9c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -89,6 +89,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ if (bmd->object != NULL) {
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
+ }
+ /* We need own transformation as well. */
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+}
+
#ifdef WITH_MOD_BOOLEAN
static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
{
@@ -193,6 +208,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.h b/source/blender/modifiers/intern/MOD_boolean_util.h
index 04d76d45652..00d7c37b266 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.h
+++ b/source/blender/modifiers/intern/MOD_boolean_util.h
@@ -33,9 +33,7 @@
#ifndef __MOD_BOOLEAN_UTIL_H__
#define __MOD_BOOLEAN_UTIL_H__
-struct Scene;
struct Object;
-struct Base;
struct DerivedMesh;
/* Performs a boolean between two mesh objects, it is assumed that both objects
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 1dc1a1f8d64..507fad466a3 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -131,6 +131,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
MPoly *mpoly, *mp;
MLoop *ml, *mloop;
MEdge *medge;
+ uintptr_t hash_num, hash_num_alt;
if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
BLI_array_randomize(faceMap, sizeof(*faceMap),
@@ -142,40 +143,44 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
*/
mpoly = mpoly_src;
mloop = mloop_src;
+ hash_num = 0;
for (i = 0; i < numFaces_dst; i++) {
mp = mpoly + faceMap[i];
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++) {
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v)))
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ void **val_p;
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(ml->v), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
+ }
}
-
+
numLoops_dst += mp->totloop;
}
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
/* get the set of edges that will be in the new mesh (i.e. all edges
* that have both verts in the new mesh)
*/
medge = medge_src;
- for (i = 0; i < numEdge_src; i++) {
+ hash_num = 0;
+ hash_num_alt = 0;
+ for (i = 0; i < numEdge_src; i++, hash_num_alt++) {
MEdge *me = medge + i;
if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
{
- j = BLI_ghash_size(edgeHash);
-
- BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
- SET_INT_IN_POINTER(i));
- BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i),
- SET_INT_IN_POINTER(j));
+ BLI_ghash_insert(edgeHash, (void *)hash_num, (void *)hash_num_alt);
+ BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num);
+ hash_num++;
}
}
}
else if (numEdges_dst) {
MEdge *medge, *me;
+ uintptr_t hash_num;
if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE)
BLI_array_randomize(edgeMap, sizeof(*edgeMap),
@@ -185,17 +190,22 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
* mapped to the new indices
*/
medge = medge_src;
+ hash_num = 0;
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
for (i = 0; i < numEdges_dst; i++) {
+ void **val_p;
me = medge + edgeMap[i];
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v1),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v1), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
}
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v2), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
}
}
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
/* get the set of edges that will be in the new mesh */
for (i = 0; i < numEdges_dst; i++) {
@@ -319,6 +329,7 @@ ModifierTypeInfo modifierType_Build = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 3bdc62e124c..7c3d65a5c9a 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -121,6 +121,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CastModifierData *cmd = (CastModifierData *)md;
+ if (cmd->object != NULL) {
+ DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ }
+}
+
static void sphere_do(
CastModifierData *cmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
@@ -500,6 +512,7 @@ ModifierTypeInfo modifierType_Cast = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index d76427cd6ee..25fd54d1d3e 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -98,7 +98,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
if (derivedData == NULL && clmd->sim_parms->shapekey_rest) {
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
clmd->sim_parms->shapekey_rest);
- if (kb->data != NULL) {
+ if (kb && kb->data != NULL) {
float (*layerorco)[3];
if (!(layerorco = DM_get_vert_data_layer(dm, CD_CLOTH_ORCO))) {
DM_add_vert_layer(dm, CD_CLOTH_ORCO, CD_CALLOC, NULL);
@@ -140,6 +140,27 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ if (clmd != NULL) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
+ if (coll_clmd) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
+ }
+ }
+ }
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
CustomDataMask dataMask = 0;
@@ -251,6 +272,7 @@ ModifierTypeInfo modifierType_Cloth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 130e332ef69..931f82c98e9 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -241,6 +241,7 @@ ModifierTypeInfo modifierType_Collision = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
new file mode 100644
index 00000000000..d5b4daca3b7
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -0,0 +1,769 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2015 by the Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Jack Simpson,
+* Campbell Barton
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/** \file blender/modifiers/intern/MOD_correctivesmooth.c
+ * \ingroup modifiers
+ *
+ * Method of smoothing deformation, also known as 'delta-mush'.
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#include "BLI_strict_flags.h"
+
+
+// #define DEBUG_TIME
+
+#include "PIL_time.h"
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+/* minor optimization, calculate this inline */
+#define USE_TANGENT_CALC_INLINE
+
+static void initData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ csmd->bind_coords = NULL;
+ csmd->bind_coords_num = 0;
+
+ csmd->lambda = 0.5f;
+ csmd->repeat = 5;
+ csmd->flag = 0;
+ csmd->smooth_type = MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE;
+
+ csmd->defgrp_name[0] = '\0';
+
+ csmd->delta_cache = NULL;
+}
+
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
+
+ modifier_copyData_generic(md, target);
+
+ if (csmd->bind_coords) {
+ tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
+ }
+
+ tcsmd->delta_cache = NULL;
+ tcsmd->delta_cache_num = 0;
+}
+
+
+static void freeBind(CorrectiveSmoothModifierData *csmd)
+{
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ csmd->bind_coords_num = 0;
+}
+
+
+static void freeData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ freeBind(csmd);
+}
+
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CustomDataMask dataMask = 0;
+ /* ask for vertex groups if we need them */
+ if (csmd->defgrp_name[0]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
+ return dataMask;
+}
+
+
+/* check individual weights for changes and cache values */
+static void dm_get_weights(
+ MDeformVert *dvert, const int defgrp_index,
+ const unsigned int numVerts, const bool use_invert_vgroup,
+ float *smooth_weights)
+{
+ unsigned int i;
+
+ for (i = 0; i < numVerts; i++, dvert++) {
+ const float w = defvert_find_weight(dvert, defgrp_index);
+
+ if (use_invert_vgroup == false) {
+ smooth_weights[i] = w;
+ }
+ else {
+ smooth_weights[i] = 1.0f - w;
+ }
+ }
+}
+
+
+static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
+{
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = dm->getEdgeArray(dm);
+ unsigned int mpoly_num, medge_num, i;
+ unsigned short *boundaries;
+
+ mpoly_num = (unsigned int)dm->getNumPolys(dm);
+ medge_num = (unsigned int)dm->getNumEdges(dm);
+
+ boundaries = MEM_callocN(medge_num * sizeof(*boundaries), __func__);
+
+ /* count the number of adjacent faces */
+ for (i = 0; i < mpoly_num; i++) {
+ const MPoly *p = &mpoly[i];
+ const int totloop = p->totloop;
+ int j;
+ for (j = 0; j < totloop; j++) {
+ boundaries[mloop[p->loopstart + j].e]++;
+ }
+ }
+
+ for (i = 0; i < medge_num; i++) {
+ if (boundaries[i] == 1) {
+ smooth_weights[medge[i].v1] = 0.0f;
+ smooth_weights[medge[i].v2] = 0.0f;
+ }
+ }
+
+ MEM_freeN(boundaries);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Simple Weighted Smoothing
+ *
+ * (average of surrounding verts)
+ */
+static void smooth_iter__simple(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ const float lambda = csmd->lambda;
+ unsigned int i;
+
+ const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
+ const MEdge *edges = dm->getEdgeArray(dm);
+ float *vertex_edge_count_div;
+
+ struct SmoothingData_Simple {
+ float delta[3];
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+ vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+
+ /* calculate as floats to avoid int->float conversion in #smooth_iter */
+ for (i = 0; i < numEdges; i++) {
+ vertex_edge_count_div[edges[i].v1] += 1.0f;
+ vertex_edge_count_div[edges[i].v2] += 1.0f;
+ }
+
+ /* a little confusing, but we can include 'lambda' and smoothing weight
+ * here to avoid multiplying for every iteration */
+ if (smooth_weights == NULL) {
+ for (i = 0; i < numVerts; i++) {
+ vertex_edge_count_div[i] =
+ lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ vertex_edge_count_div[i] =
+ smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
+ }
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Main Smoothing Loop */
+
+ while (iterations--) {
+ for (i = 0; i < numEdges; i++) {
+ struct SmoothingData_Simple *sd_v1;
+ struct SmoothingData_Simple *sd_v2;
+ float edge_dir[3];
+
+ sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
+
+ sd_v1 = &smooth_data[edges[i].v1];
+ sd_v2 = &smooth_data[edges[i].v2];
+
+ add_v3_v3(sd_v1->delta, edge_dir);
+ sub_v3_v3(sd_v2->delta, edge_dir);
+ }
+
+
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Simple *sd = &smooth_data[i];
+ madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
+ /* zero for the next iteration (saves memset on entire array) */
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+
+ MEM_freeN(vertex_edge_count_div);
+ MEM_freeN(smooth_data);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Edge-Length Weighted Smoothing
+ */
+static void smooth_iter__length_weight(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ const float eps = FLT_EPSILON * 10.0f;
+ const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
+ /* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
+ * and 2.0 rarely spikes, double the value for consistent behavior. */
+ const float lambda = csmd->lambda * 2.0f;
+ const MEdge *edges = dm->getEdgeArray(dm);
+ float *vertex_edge_count;
+ unsigned int i;
+
+ struct SmoothingData_Weighted {
+ float delta[3];
+ float edge_length_sum;
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+
+ /* calculate as floats to avoid int->float conversion in #smooth_iter */
+ vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+ for (i = 0; i < numEdges; i++) {
+ vertex_edge_count[edges[i].v1] += 1.0f;
+ vertex_edge_count[edges[i].v2] += 1.0f;
+ }
+
+
+ /* -------------------------------------------------------------------- */
+ /* Main Smoothing Loop */
+
+ while (iterations--) {
+ for (i = 0; i < numEdges; i++) {
+ struct SmoothingData_Weighted *sd_v1;
+ struct SmoothingData_Weighted *sd_v2;
+ float edge_dir[3];
+ float edge_dist;
+
+ sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
+ edge_dist = len_v3(edge_dir);
+
+ /* weight by distance */
+ mul_v3_fl(edge_dir, edge_dist);
+
+
+ sd_v1 = &smooth_data[edges[i].v1];
+ sd_v2 = &smooth_data[edges[i].v2];
+
+ add_v3_v3(sd_v1->delta, edge_dir);
+ sub_v3_v3(sd_v2->delta, edge_dir);
+
+ sd_v1->edge_length_sum += edge_dist;
+ sd_v2->edge_length_sum += edge_dist;
+ }
+
+ if (smooth_weights == NULL) {
+ /* fast-path */
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Weighted *sd = &smooth_data[i];
+ /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+#if 0
+ /* first calculate the new location */
+ mul_v3_fl(sd->delta, 1.0f / div);
+ /* then interpolate */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
+#else
+ /* do this in one step */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
+#endif
+ }
+ /* zero for the next iteration (saves memset on entire array) */
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Weighted *sd = &smooth_data[i];
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+ const float lambda_w = lambda * smooth_weights[i];
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
+ }
+
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ }
+
+ MEM_freeN(vertex_edge_count);
+ MEM_freeN(smooth_data);
+}
+
+
+static void smooth_iter(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ switch (csmd->smooth_type) {
+ case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
+ smooth_iter__length_weight(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+
+ /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
+ default:
+ smooth_iter__simple(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+ }
+}
+
+static void smooth_verts(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ float (*vertexCos)[3], unsigned int numVerts)
+{
+ float *smooth_weights = NULL;
+
+ if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
+
+ smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__);
+
+ if (dvert) {
+ dm_get_weights(
+ dvert, defgrp_index,
+ numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
+ smooth_weights);
+ }
+ else {
+ copy_vn_fl(smooth_weights, (int)numVerts, 1.0f);
+ }
+
+ if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
+ dm_get_boundaries(dm, smooth_weights);
+ }
+ }
+
+ smooth_iter(csmd, dm, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+
+ if (smooth_weights) {
+ MEM_freeN(smooth_weights);
+ }
+}
+
+/**
+ * finalize after accumulation.
+ */
+static void calc_tangent_ortho(float ts[3][3])
+{
+ float v_tan_a[3], v_tan_b[3];
+ float t_vec_a[3], t_vec_b[3];
+
+ normalize_v3(ts[2]);
+
+ copy_v3_v3(v_tan_a, ts[0]);
+ copy_v3_v3(v_tan_b, ts[1]);
+
+ cross_v3_v3v3(ts[1], ts[2], v_tan_a);
+ mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);
+
+ /* orthognalise tangent */
+ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
+ sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);
+
+ /* orthognalise bitangent */
+ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
+ mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
+ sub_v3_v3(ts[1], t_vec_a);
+ sub_v3_v3(ts[1], t_vec_b);
+
+ normalize_v3(ts[0]);
+ normalize_v3(ts[1]);
+}
+
+/**
+ * accumulate edge-vectors from all polys.
+ */
+static void calc_tangent_loop_accum(
+ const float v_dir_prev[3],
+ const float v_dir_next[3],
+ float r_tspace[3][3])
+{
+ add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next);
+
+ if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) {
+ const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev)));
+ float nor[3];
+
+ cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
+ normalize_v3(nor);
+
+ cross_v3_v3v3(r_tspace[0], r_tspace[1], nor);
+
+ mul_v3_fl(nor, weight);
+ /* accumulate weighted normals */
+ add_v3_v3(r_tspace[2], nor);
+ }
+}
+
+
+static void calc_tangent_spaces(
+ DerivedMesh *dm, float (*vertexCos)[3],
+ float (*r_tangent_spaces)[3][3])
+{
+ const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
+#ifndef USE_TANGENT_CALC_INLINE
+ const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+#endif
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ unsigned int i;
+
+ for (i = 0; i < mpoly_num; i++) {
+ const MPoly *mp = &mpoly[i];
+ const MLoop *l_next = &mloop[mp->loopstart];
+ const MLoop *l_term = l_next + mp->totloop;
+ const MLoop *l_prev = l_term - 2;
+ const MLoop *l_curr = l_term - 1;
+
+ /* loop directions */
+ float v_dir_prev[3], v_dir_next[3];
+
+ /* needed entering the loop */
+ sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
+ normalize_v3(v_dir_prev);
+
+ for (;
+ l_next != l_term;
+ l_prev = l_curr, l_curr = l_next, l_next++)
+ {
+ float (*ts)[3] = r_tangent_spaces[l_curr->v];
+
+ /* re-use the previous value */
+#if 0
+ sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
+ normalize_v3(v_dir_prev);
+#endif
+ sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
+ normalize_v3(v_dir_next);
+
+ calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);
+
+ copy_v3_v3(v_dir_prev, v_dir_next);
+ }
+ }
+
+ /* do inline */
+#ifndef USE_TANGENT_CALC_INLINE
+ for (i = 0; i < mvert_num; i++) {
+ float (*ts)[3] = r_tangent_spaces[i];
+ calc_tangent_ortho(ts);
+ }
+#endif
+}
+
+/**
+ * This calculates #CorrectiveSmoothModifierData.delta_cache
+ * It's not run on every update (during animation for example).
+ */
+static void calc_deltas(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ const float (*rest_coords)[3], unsigned int numVerts)
+{
+ float (*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
+ float (*tangent_spaces)[3][3];
+ unsigned int i;
+
+ tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__);
+
+ if (csmd->delta_cache_num != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache);
+ }
+
+ /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
+ if (!csmd->delta_cache) {
+ csmd->delta_cache_num = numVerts;
+ csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__);
+ }
+
+ smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
+
+ calc_tangent_spaces(dm, smooth_vertex_coords, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float imat[3][3], delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
+ if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
+ transpose_m3_m3(imat, tangent_spaces[i]);
+ }
+ mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ MEM_freeN(smooth_vertex_coords);
+}
+
+
+static void correctivesmooth_modifier_do(
+ ModifierData *md, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ struct BMEditMesh *em)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ const bool force_delta_cache_update =
+ /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
+ (((ID *)ob->data)->flag & LIB_ID_RECALC));
+
+ bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
+ MDeformVert *dvert = NULL;
+ int defgrp_index;
+
+ modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);
+
+ /* if rest bind_coords not are defined, set them (only run during bind) */
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
+ /* signal to recalculate, whoever sets MUST also free bind coords */
+ (csmd->bind_coords_num == (unsigned int)-1))
+ {
+ BLI_assert(csmd->bind_coords == NULL);
+ csmd->bind_coords = MEM_dupallocN(vertexCos);
+ csmd->bind_coords_num = numVerts;
+ BLI_assert(csmd->bind_coords != NULL);
+ }
+
+ if (UNLIKELY(use_only_smooth)) {
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+ return;
+ }
+
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
+ modifier_setError(md, "Bind data required");
+ goto error;
+ }
+
+ /* If the number of verts has changed, the bind is invalid, so we do nothing */
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ if (csmd->bind_coords_num != numVerts) {
+ modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
+ goto error;
+ }
+ }
+ else {
+ /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
+ if (ob->type != OB_MESH) {
+ modifier_setError(md, "Object is not a mesh");
+ goto error;
+ }
+ else {
+ unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
+
+ if (me_numVerts != numVerts) {
+ modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
+ goto error;
+ }
+ }
+ }
+
+ /* check to see if our deltas are still valid */
+ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ const float (*rest_coords)[3];
+ bool is_rest_coords_alloc = false;
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* caller needs to do sanity check here */
+ csmd->bind_coords_num = numVerts;
+ rest_coords = (const float (*)[3])csmd->bind_coords;
+ }
+ else {
+ int me_numVerts;
+ rest_coords = (const float (*)[3]) ((em) ?
+ BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
+ BKE_mesh_vertexCos_get(ob->data, &me_numVerts));
+
+ BLI_assert((unsigned int)me_numVerts == numVerts);
+ is_rest_coords_alloc = true;
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth_deltas);
+#endif
+
+ calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth_deltas);
+#endif
+ if (is_rest_coords_alloc) {
+ MEM_freeN((void *)rest_coords);
+ }
+ }
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* this could be a check, but at this point it _must_ be valid */
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ }
+
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth);
+#endif
+
+ /* do the actual delta mush */
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+
+ {
+ unsigned int i;
+
+ float (*tangent_spaces)[3][3];
+
+ /* calloc, since values are accumulated */
+ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);
+
+ calc_tangent_spaces(dm, vertexCos, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ add_v3_v3(vertexCos[i], delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth);
+#endif
+
+ return;
+
+ /* when the modifier fails to execute */
+error:
+ MEM_SAFE_FREE(csmd->delta_cache);
+ csmd->delta_cache_num = 0;
+
+}
+
+
+static void deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+{
+ DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, NULL);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+static void deformVertsEM(
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, editData);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+ModifierTypeInfo modifierType_CorrectiveSmooth = {
+ /* name */ "CorrectiveSmooth",
+ /* structName */ "CorrectiveSmoothModifierData",
+ /* structSize */ sizeof(CorrectiveSmoothModifierData),
+ /* 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 */ requiredDataMask,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index d53bac390a6..1488296caf9 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -45,6 +45,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -108,6 +109,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CurveModifierData *cmd = (CurveModifierData *)md;
+ if (cmd->object != NULL) {
+ /* TODO(sergey): Need to do the same eval_flags trick for path
+ * as happening in legacy depsgraph callback.
+ */
+ /* TODO(sergey): Currently path is evaluated as a part of modifier stack,
+ * might be changed in the future.
+ */
+ 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);
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -156,6 +176,7 @@ ModifierTypeInfo modifierType_Curve = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index d13ca6e5bb7..e133c4785b7 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -147,6 +147,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
+ if (dtmd->ob_source != NULL) {
+ DEG_add_object_relation(node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
@@ -213,6 +225,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
#undef HIGH_POLY_WARNING
#undef DT_TYPES_AFFECT_MESH
+static void copyData(ModifierData *md, ModifierData *target)
+{
+#if 0
+ DataTransferModifierData *dtmd = (DecimateModifierData *) md;
+ DataTransferModifierData *tdtmd = (DecimateModifierData *) target;
+#endif
+ modifier_copyData_generic(md, target);
+}
+
ModifierTypeInfo modifierType_DataTransfer = {
/* name */ "DataTransfer",
/* structName */ "DataTransferModifierData",
@@ -223,7 +244,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_UsesPreview,
- /* copyData */ NULL,
+ /* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
@@ -235,6 +256,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 8a92deec8eb..14468ab7c12 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -61,6 +61,7 @@ static void initData(ModifierData *md)
dmd->percent = 1.0;
dmd->angle = DEG2RADF(5.0f);
+ dmd->defgrp_factor = 1.0;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -78,7 +79,9 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
CustomDataMask dataMask = 0;
/* ask for vertexgroups if we need them */
- if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
+ if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
return dataMask;
}
@@ -130,7 +133,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
- if (dmd->defgrp_name[0]) {
+ if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
MDeformVert *dvert;
int defgrp_index;
@@ -144,14 +147,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
for (i = 0; i < vert_tot; i++) {
- const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
- vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+ vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
}
}
else {
for (i = 0; i < vert_tot; i++) {
- const float f = defvert_find_weight(&dvert[i], defgrp_index);
- vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+ vweights[i] = defvert_find_weight(&dvert[i], defgrp_index);
}
}
}
@@ -163,8 +164,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
switch (dmd->mode) {
case MOD_DECIM_MODE_COLLAPSE:
{
- const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
- BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate);
+ const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
+ BM_mesh_decimate_collapse(bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate);
break;
}
case MOD_DECIM_MODE_UNSUBDIV:
@@ -174,7 +175,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
case MOD_DECIM_MODE_DISSOLVE:
{
- const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
+ const bool do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
break;
}
@@ -224,6 +225,7 @@ ModifierTypeInfo modifierType_Decimate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index e377445fed8..2921472fe99 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -171,6 +171,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData *)md;
+ if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+}
+
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
@@ -302,6 +317,7 @@ ModifierTypeInfo modifierType_Displace = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index c6999468dc3..95bc4706dc9 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -38,6 +38,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -135,6 +136,26 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ /* Add relation from canvases to all brush objects. */
+ if (pmd->canvas != NULL) {
+ Base *base = scene->base.first;
+ for (; base; base = base->next) {
+ DynamicPaintModifierData *pmd2 =
+ (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
+ if (pmd2 && pmd2->brush && ob != base->object) {
+ DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -187,6 +208,7 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index fa29921b325..4441edb299b 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -158,6 +158,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 32a6303d19d..82600421736 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -771,7 +771,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
for (i = 0; i < curdupface; i++) {
mf = CDDM_get_tessface(splitdm, i);
- test_index_face(mf, &splitdm->faceData, i, (mf->flag & ME_FACE_SEL ? 4 : 3));
+ test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
}
BLI_edgehash_free(edgehash, NULL);
@@ -1058,6 +1058,7 @@ ModifierTypeInfo modifierType_Explode = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index 6344ec83a31..c202c5e1cb4 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -44,6 +44,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
#include "MEM_guardedalloc.h"
@@ -71,6 +72,9 @@ static void copyData(ModifierData *md, ModifierData *target)
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);
+ }
}
@@ -123,6 +127,32 @@ static void updateDepgraph(
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
+ if (fluidmd && fluidmd->fss) {
+ if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ FluidsimModifierData *fluidmdtmp =
+ (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
+
+ /* Only put dependencies from NON-DOMAIN fluids in here. */
+ if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
+ }
+ }
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -151,6 +181,7 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 10223d3880e..3a10fabbb8e 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -129,6 +129,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ HookModifierData *hmd = (HookModifierData *)md;
+ if (hmd->object != NULL) {
+ if (hmd->subtarget[0]) {
+ /* TODO(sergey): Hpw do we add relation to bone here? */
+ //DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_EVAL_POSE, "Hook Modifier");
+ DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
+ }
+ else {
+ DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ }
+}
+
struct HookData_cb {
float (*vertexCos)[3];
@@ -403,6 +422,7 @@ ModifierTypeInfo modifierType_Hook = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index a4f6d005d94..c3cfafb7e27 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -862,6 +862,7 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 93cd92196b2..a142d18a6d3 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -716,6 +716,7 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* freeData */ NULL,
/* isDisabled */ is_disabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 60caf523a97..b8975beaf83 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -107,6 +107,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -155,6 +167,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index e77225f3617..06fbab65d7b 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -50,6 +50,7 @@
#include "BKE_deform.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "BLI_strict_flags.h"
@@ -94,6 +95,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MaskModifierData *mmd = (MaskModifierData *)md;
+ if (mmd->ob_arm) {
+ bArmature *arm = (bArmature *)mmd->ob_arm->data;
+ /* Tag relationship in depsgraph, but also on the armature. */
+ /* TODO(sergey): Is it a proper relation here? */
+ DEG_add_object_relation(node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
+ arm->flag |= ARM_HAS_VIZ_DEPS;
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
@@ -385,6 +402,7 @@ ModifierTypeInfo modifierType_Mask = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index db50d49f790..92926ed9424 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -313,6 +313,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h
index f3b5f43009d..241806f49e1 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_util.h
+++ b/source/blender/modifiers/intern/MOD_meshcache_util.h
@@ -27,8 +27,6 @@
#ifndef __MOD_MESHCACHE_UTIL_H__
#define __MOD_MESHCACHE_UTIL_H__
-struct MPoly;
-struct MLoop;
/* MOD_meshcache_mdd.c */
bool MOD_meshcache_read_mdd_index(FILE *fp,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 3ceed4a970d..22148d1f5ae 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -139,6 +139,19 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
+ if (mmd->object != NULL) {
+ /* TODO(sergey): Do we need transform component here? */
+ DEG_add_object_relation(node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
+ }
+}
+
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3])
{
MDefCell *cell;
@@ -521,6 +534,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 5285bc4124d..d3080ca235a 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -43,7 +43,9 @@
#include "BKE_deform.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -88,13 +90,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ if (mmd->mirror_ob != NULL) {
+ DEG_add_object_relation(node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+}
+
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
int axis)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
- const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE);
+ const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
int tot_vtargetmap = 0; /* total merge vertices */
DerivedMesh *result;
@@ -361,6 +375,7 @@ ModifierTypeInfo modifierType_Mirror = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 4754813a744..90ad1bdfdc2 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -162,6 +162,7 @@ ModifierTypeInfo modifierType_Multires = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index 579f65a9c50..d9d9ba2966d 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -68,6 +68,7 @@ ModifierTypeInfo modifierType_None = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index edb7278789b..87d75c6f1a7 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -60,7 +60,8 @@ static void generate_vert_coordinates(
/* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */
if (ob_center) {
- copy_v3_v3(r_size, ob_center->size);
+ /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */
+ abs_v3_v3(r_size, ob_center->size);
}
else {
minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts);
@@ -79,13 +80,14 @@ static void generate_vert_coordinates(
}
if (ob_center) {
- /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
- float mat[4][4];
+ float inv_obmat[4][4];
- /* Get ob_center coordinates in ob local coordinates. */
- invert_m4_m4(mat, ob_center->obmat);
- mul_m4_m4m4(mat, mat, ob->obmat);
- copy_v3_v3(diff, mat[3]);
+ /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
+ /* Get ob_center (world) coordinates in ob local coordinates.
+ * No need to take into accound ob_center's space here, see T44027. */
+ invert_m4_m4(inv_obmat, ob->obmat);
+ mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]);
+ negate_v3(diff);
do_diff = true;
}
@@ -479,6 +481,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ if (smd->target) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "NormalEdit Modifier");
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
{
return normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
@@ -506,6 +520,7 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 1c8dcdff46d..913c2f25c15 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -48,14 +48,14 @@ static void init_cache_data(Object *ob, struct OceanModifierData *omd)
{
const char *relbase = modifier_path_relbase(ob);
- omd->oceancache = BKE_init_ocean_cache(omd->cachepath, relbase,
+ omd->oceancache = BKE_ocean_init_cache(omd->cachepath, relbase,
omd->bakestart, omd->bakeend, omd->wave_scale,
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
}
static void clear_cache_data(struct OceanModifierData *omd)
{
- BKE_free_ocean_cache(omd->oceancache);
+ BKE_ocean_free_cache(omd->oceancache);
omd->oceancache = NULL;
omd->cached = false;
}
@@ -72,8 +72,8 @@ static void init_ocean_modifier(struct OceanModifierData *omd)
do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
- BKE_free_ocean_data(omd->ocean);
- BKE_init_ocean(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
+ BKE_ocean_free_data(omd->ocean);
+ BKE_ocean_init(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
omd->spatial_size, omd->spatial_size,
omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
omd->depth, omd->time,
@@ -85,7 +85,7 @@ static void simulate_ocean_modifier(struct OceanModifierData *omd)
{
if (!omd || !omd->ocean) return;
- BKE_simulate_ocean(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
+ BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
}
#endif /* WITH_OCEANSIM */
@@ -133,7 +133,7 @@ static void initData(ModifierData *md)
omd->foam_fade = 0.98;
omd->foamlayername[0] = '\0'; /* layer name empty by default */
- omd->ocean = BKE_add_ocean();
+ omd->ocean = BKE_ocean_add();
init_ocean_modifier(omd);
simulate_ocean_modifier(omd);
#else /* WITH_OCEANSIM */
@@ -147,9 +147,9 @@ static void freeData(ModifierData *md)
#ifdef WITH_OCEANSIM
OceanModifierData *omd = (OceanModifierData *) md;
- BKE_free_ocean(omd->ocean);
+ BKE_ocean_free(omd->ocean);
if (omd->oceancache)
- BKE_free_ocean_cache(omd->oceancache);
+ BKE_ocean_free_cache(omd->oceancache);
#else /* WITH_OCEANSIM */
/* unused */
(void)md;
@@ -195,7 +195,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tomd->bakeend = omd->bakeend;
tomd->oceancache = NULL;
- tomd->ocean = BKE_add_ocean();
+ tomd->ocean = BKE_ocean_add();
init_ocean_modifier(tomd);
simulate_ocean_modifier(tomd);
#else /* WITH_OCEANSIM */
@@ -426,7 +426,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
/* update modifier */
if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
- omd->ocean = BKE_add_ocean();
+ omd->ocean = BKE_ocean_add();
if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
init_ocean_modifier(omd);
if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
@@ -437,7 +437,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
/* do ocean simulation */
if (omd->cached == true) {
if (!omd->oceancache) init_cache_data(ob, omd);
- BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra);
+ BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
}
else {
simulate_ocean_modifier(omd);
@@ -580,6 +580,7 @@ ModifierTypeInfo modifierType_Ocean = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 29ba7dda5db..cb6234d50b7 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -51,7 +51,7 @@
#include "BKE_pointcache.h"
#include "depsgraph_private.h"
-
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -127,6 +127,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
+ if (pimd->ob != NULL) {
+ DEG_add_object_relation(node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
+ }
+}
+
static void foreachObjectLink(ModifierData *md, Object *ob,
ObjectWalkFunc walk, void *userData)
{
@@ -448,6 +460,7 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 9860daeda4c..de1b11eddd9 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -206,6 +206,7 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 6d76dc51ac7..9df064db44d 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -232,6 +232,7 @@ ModifierTypeInfo modifierType_Remesh = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 2c9f5e32440..2e431884845 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,6 +46,8 @@
#include "BKE_cdderivedmesh.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
@@ -138,15 +140,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm = derivedData;
DerivedMesh *result;
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- const int useRenderParams = flag & MOD_APPLY_RENDER;
+ const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0;
int *origindex;
int mpoly_index = 0;
unsigned int step;
unsigned int i, j;
unsigned int i1, i2;
- unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps;
- const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;
+ unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
+ const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
const int quad_ord[4] = {
do_flip ? 3 : 0,
@@ -156,9 +158,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
};
const int quad_ord_ofs[4] = {
do_flip ? 2 : 0,
- do_flip ? 1 : 1,
+ 1,
do_flip ? 0 : 2,
- do_flip ? 3 : 3,
+ 3,
};
unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
@@ -1074,6 +1076,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ScrewModifierData *ltmd = (ScrewModifierData *)md;
+ if (ltmd->ob_axis != NULL) {
+ DEG_add_object_relation(node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
+ }
+}
+
static void foreachObjectLink(
ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
@@ -1107,6 +1121,7 @@ ModifierTypeInfo modifierType_Screw = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index f3327a03f2c..a543aac74b9 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -138,6 +138,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index fd583c43d6e..91be0c40059 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -159,6 +159,23 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ if (smd->target != NULL) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+ if (smd->auxTarget != NULL) {
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+}
+
static bool dependsOnNormals(ModifierData *md)
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
@@ -191,6 +208,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 0e1cb125a47..706a296f5a1 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -298,6 +298,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
+ if (smd->origin != NULL) {
+ DEG_add_object_relation(node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -362,6 +374,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index bd16fd07044..1b8b29666e2 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -104,6 +104,9 @@ typedef struct Frame {
/* Merge to target frame/corner (no merge if frame is null) */
struct Frame *frame;
int corner;
+ /* checked to avoid chaining.
+ * (merging when we're already been referenced), see T39775 */
+ unsigned int is_target : 1;
} merge[4];
/* For hull frames, whether each vertex is detached or not */
@@ -249,6 +252,7 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
/* Apply face attributes to hull output */
BMO_ITER (f, &oiter, op.slots_out, "geom.out", BM_FACE) {
+ BM_face_normal_update(f);
if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING)
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
f->mat_nr = so->mat_nr;
@@ -362,7 +366,7 @@ static void merge_frame_corners(Frame **frames, int totframe)
/* Compare with each corner of all other frames... */
for (l = 0; l < 4; l++) {
- if (frames[k]->merge[l].frame)
+ if (frames[k]->merge[l].frame || frames[k]->merge[l].is_target)
continue;
/* Some additional concerns that could be checked
@@ -392,6 +396,7 @@ static void merge_frame_corners(Frame **frames, int totframe)
frames[k]->merge[l].frame = frames[i];
frames[k]->merge[l].corner = j;
+ frames[i]->merge[j].is_target = true;
/* Can't merge another corner into the same
* frame corner, so move on to frame k+1 */
@@ -960,6 +965,7 @@ static void add_poly(SkinOutput *so,
BLI_assert(v1 && v2 && v3);
f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, NULL, BM_CREATE_NO_DOUBLE, true);
+ BM_face_normal_update(f);
if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING)
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
f->mat_nr = so->mat_nr;
@@ -1421,6 +1427,9 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
if (adj[0]->len == 3 && adj[1]->len == 3) {
BMVert *quad[4];
+ BLI_assert(BM_face_is_normal_valid(adj[0]));
+ BLI_assert(BM_face_is_normal_valid(adj[1]));
+
/* Construct quad using the two triangles adjacent to
* the edge */
quad_from_tris(e, adj, quad);
@@ -1783,6 +1792,9 @@ static BMesh *build_skin(SkinNode *skin_nodes,
skin_output_connections(&so, skin_nodes, medge, totedge);
hull_merge_triangles(&so, smd);
+ bmesh_edit_end(so.bm, 0);
+ BMO_pop(so.bm);
+
return so.bm;
}
@@ -1793,7 +1805,7 @@ static void skin_set_orig_indices(DerivedMesh *dm)
totpoly = dm->getNumPolys(dm);
orig = CustomData_add_layer(&dm->polyData, CD_ORIGINDEX,
CD_CALLOC, NULL, totpoly);
- fill_vn_i(orig, totpoly, ORIGINDEX_NONE);
+ copy_vn_i(orig, totpoly, ORIGINDEX_NONE);
}
/*
@@ -1844,7 +1856,6 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
result = CDDM_from_bmesh(bm, false);
BM_mesh_free(bm);
- CDDM_calc_edges(result);
result->dirty |= DM_DIRTY_NORMALS;
skin_set_orig_indices(result);
@@ -1930,6 +1941,7 @@ ModifierTypeInfo modifierType_Skin = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 74409498ca3..657c4e09d96 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -53,6 +53,7 @@
#include "BKE_smoke.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -227,6 +228,111 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
+ Object *object2)
+{
+ SmokeModifierData *smd;
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
+ if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
+ ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
+ {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Smoke Flow/Coll");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Smoke Flow/Coll");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_flow_coll_object_new(node, go->ob);
+ }
+ }
+}
+
+static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node,
+ Object *object,
+ Object *object2)
+{
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_field_source_object_new(node, object, go->ob);
+ }
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ Base *base;
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (smd->domain->fluid_group || smd->domain->coll_group) {
+ GroupObject *go = NULL;
+ if (smd->domain->fluid_group != NULL) {
+ for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Flow");
+ }
+ }
+ }
+ }
+ if (smd->domain->coll_group != NULL) {
+ for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Coll");
+ }
+ }
+ }
+ }
+ }
+ else {
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ base = scene->base.first;
+ for (; base; base = base->next) {
+ update_depsgraph_flow_coll_object_new(node, base->object);
+ }
+ }
+ /* add relation to all "smoke flow" force fields */
+ base = scene->base.first;
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ for (; base; base = base->next) {
+ update_depsgraph_field_source_object_new(node, ob, base->object);
+ }
+ }
+}
+
static void foreachIDLink(ModifierData *md, Object *ob,
IDWalkFunc walk, void *userData)
{
@@ -268,6 +374,7 @@ ModifierTypeInfo modifierType_Smoke = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index d1ad8f1fcfc..d45c8528510 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -262,6 +262,7 @@ ModifierTypeInfo modifierType_Smooth = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 5f5347a46b0..d958badc33c 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -80,6 +80,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 08b8854c728..ca2dcfec3a3 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -255,7 +255,7 @@ static DerivedMesh *applyModifier(
/* weights */
MDeformVert *dvert;
- const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
+ const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
/* array size is doubled in case of using a shell */
@@ -298,7 +298,7 @@ static DerivedMesh *applyModifier(
/* save doing 2 loops here... */
#if 0
- fill_vn_i(edge_users, numEdges, INVALID_UNUSED);
+ copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
#endif
for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
@@ -505,7 +505,7 @@ static DerivedMesh *applyModifier(
unsigned int i;
vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
- fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
+ copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
@@ -672,7 +672,7 @@ static DerivedMesh *applyModifier(
float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const float offset_sq = offset * offset;
- fill_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
+ copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
@@ -961,6 +961,7 @@ ModifierTypeInfo modifierType_Solidify = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index f17858264f8..2a62a9e6081 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -88,7 +88,7 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
SubsurfModifierData *smd = (SubsurfModifierData *) md;
int levels = (useRenderParams) ? smd->renderLevels : smd->levels;
- return get_render_subsurf_level(&md->scene->r, levels) == 0;
+ return get_render_subsurf_level(&md->scene->r, levels, useRenderParams != 0) == 0;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
@@ -159,6 +159,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 1c462f12f9f..3d998f2d95a 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -186,6 +186,7 @@ ModifierTypeInfo modifierType_Surface = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 592ab4194ec..194a46b6f28 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -119,6 +119,7 @@ ModifierTypeInfo modifierType_Triangulate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index c23c22b5fec..be6f7af7791 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -59,7 +59,7 @@
#include "BLI_threads.h"
#endif
-void modifier_init_texture(Scene *scene, Tex *tex)
+void modifier_init_texture(const Scene *scene, Tex *tex)
{
if (!tex)
return;
@@ -306,5 +306,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Wireframe);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
+ INIT_TYPE(CorrectiveSmooth);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index cb851a51c64..b74ff9c2a25 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -31,16 +31,16 @@
/* so modifier types match their defines */
#include "MOD_modifiertypes.h"
-struct CustomData;
+#include "DEG_depsgraph_build.h"
+
struct DerivedMesh;
struct MDeformVert;
struct ModifierData;
struct Object;
struct Scene;
struct Tex;
-struct TexResult;
-void modifier_init_texture(struct Scene *scene, struct Tex *texture);
+void modifier_init_texture(const struct Scene *scene, struct Tex *texture);
void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm,
float (*co)[3], float (*texco)[3], int numVerts);
void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index a10386a6f41..1b1474ee666 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -51,7 +51,9 @@
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -122,6 +124,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData *)md;
+ int i;
+ for (i = 0; i < umd->num_projectors; ++i) {
+ if (umd->projectors[i] != NULL) {
+ DEG_add_object_relation(node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ }
+ }
+}
+
typedef struct Projector {
Object *ob; /* object this projector is derived from */
float projmat[4][4]; /* projection matrix */
@@ -139,7 +156,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
Image *image = umd->image;
MPoly *mpoly, *mp;
MLoop *mloop;
- int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
+ const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0;
Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
int num_projectors = 0;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -369,6 +386,7 @@ ModifierTypeInfo modifierType_UVProject = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index f41705d1aac..3c4ca66485d 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -229,6 +229,30 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
uv_warp_deps_object_bone(forest, obNode, umd->object_dst, umd->bone_dst);
}
+static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename)
+{
+ if (object != NULL) {
+ if (bonename[0])
+ DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier");
+ else
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVWarpModifierData *umd = (UVWarpModifierData *) md;
+
+ uv_warp_deps_object_bone_new(node, umd->object_src, umd->bone_src);
+ uv_warp_deps_object_bone_new(node, umd->object_dst, umd->bone_dst);
+}
+
ModifierTypeInfo modifierType_UVWarp = {
/* name */ "UVWarp",
/* structName */ "UVWarpModifierData",
@@ -249,6 +273,7 @@ ModifierTypeInfo modifierType_UVWarp = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 9d496724ba1..ae2dbd4a37c 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -157,6 +157,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WarpModifierData *wmd = (WarpModifierData *) md;
+ if (wmd->object_from != NULL && wmd->object_to != NULL) {
+ DEG_add_object_relation(node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
+ DEG_add_object_relation(node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
+ }
+ if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
+ }
+}
+
static void warpModifier_do(WarpModifierData *wmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
@@ -372,6 +388,7 @@ ModifierTypeInfo modifierType_Warp = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 7fd830dabd4..5b98f221489 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -153,6 +153,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WaveModifierData *wmd = (WaveModifierData *)md;
+ if (wmd->objectcenter != NULL) {
+ DEG_add_object_relation(node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+ if (wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WaveModifierData *wmd = (WaveModifierData *)md;
@@ -381,6 +396,7 @@ ModifierTypeInfo modifierType_Wave = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index c4734ccd7a8..cba077a2f8d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -162,6 +164,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGEdit Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
@@ -292,6 +309,7 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 4433922f9bb..3d60c4a8b8b 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -43,6 +43,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -211,6 +213,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGMix Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
@@ -234,7 +251,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
int i;
/* Flags. */
#if 0
- int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
+ const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif
/* Get number of verts. */
@@ -422,6 +439,7 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 057674f1144..033516016d3 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -338,6 +340,24 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGProximity Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
+ if (wmd->proximity_ob_target != NULL) {
+ DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
@@ -366,7 +386,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
int i;
/* Flags. */
#if 0
- int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
+ const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif
#ifdef USE_TIMEIT
@@ -566,6 +586,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index aa5e6116516..fe21757d5c2 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -133,6 +133,7 @@ ModifierTypeInfo modifierType_Wireframe = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 9eb6c1674a3..c95daffe557 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -122,6 +122,7 @@ set(SRC
composite/nodes/node_composite_boxmask.c
composite/nodes/node_composite_ellipsemask.c
composite/nodes/node_composite_switch.c
+ composite/nodes/node_composite_switchview.c
composite/nodes/node_composite_colorcorrection.c
composite/nodes/node_composite_pixelate.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 961fdbfc0fb..0215db1dd55 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -133,6 +133,7 @@ void register_node_type_cmp_ellipsemask(void);
void register_node_type_cmp_bokehimage(void);
void register_node_type_cmp_bokehblur(void);
void register_node_type_cmp_switch(void);
+void register_node_type_cmp_switch_view(void);
void register_node_type_cmp_pixelate(void);
void register_node_type_cmp_trackpos(void);
void register_node_type_cmp_planetrackdeform(void);
diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h
index 81230456193..5c8875593e7 100644
--- a/source/blender/nodes/NOD_socket.h
+++ b/source/blender/nodes/NOD_socket.h
@@ -43,7 +43,6 @@
struct bNodeTree;
struct bNode;
-struct bNodeStack;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, int in_out);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 166fa29fca0..b33bec51c2c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -71,7 +71,7 @@ DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OU
DefNode( ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "" )
DefNode( ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "" )
-DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" )
+DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" )
DefNode( ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" )
DefNode( ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "" )
DefNode( ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "" )
@@ -202,13 +202,14 @@ DefNode( CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIP
DefNode( CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" )
DefNode( CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" )
DefNode( CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" )
+DefNode( CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" )
DefNode( CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" )
DefNode( CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" )
DefNode( CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
DefNode( CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" )
DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" )
DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" )
-DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
+DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode( CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index e616680647e..8bc61862458 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -226,12 +226,13 @@ void *COM_linker_hack = NULL;
void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int rendering, int do_preview,
const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings)
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name)
{
#ifdef WITH_COMPOSITOR
- COM_execute(rd, scene, ntree, rendering, view_settings, display_settings);
+ COM_execute(rd, scene, ntree, rendering, view_settings, display_settings, view_name);
#else
- UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings);
+ UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings, view_name);
#endif
UNUSED_VARS(do_preview);
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
index 8e279cf6d68..bbfb07a316d 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -43,7 +43,7 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
for (sock = node->outputs.first; sock; sock = sock->next) {
if (sock->cache) {
//free_compbuf(sock->cache);
- //sock->cache= NULL;
+ //sock->cache = NULL;
}
}
node->need_exec = 1;
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 34f3350c2ff..19e93447608 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -168,14 +168,21 @@ static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node,
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;
-
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, rpass->name, rpass->name);
+
+ /* 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);
/* extra socket info */
sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
sock->storage = sockdata;
@@ -183,7 +190,7 @@ static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node,
sockdata->pass_index = index;
sockdata->pass_flag = rpass->passtype;
- if (STREQ(rpass->chan_id, "RGBA")) {
+ 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;
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.c b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
index 22d16e93879..35096d57a4e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
@@ -44,7 +44,7 @@ static bNodeSocketTemplate cmp_node_map_value_out[] = {
static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_tex_mapping(TEXMAP_TYPE_POINT);
+ node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
void register_node_type_cmp_map_value(void)
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 8e602c6179c..7d1087435c2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -127,7 +127,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con
BKE_imformat_defaults(&sockdata->format);
/* use node data format by default */
sockdata->use_node_format = true;
-
+
nimf->active_input = BLI_findindex(&node->inputs, sock);
return sock;
@@ -189,7 +189,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
}
else
BKE_imformat_defaults(&nimf->format);
-
+
/* add one socket by default */
ntreeCompositOutputFileAddSocket(ntree, node, "Image", format);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c
new file mode 100644
index 00000000000..d805cf4d87f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c
@@ -0,0 +1,153 @@
+/*
+ * ***** 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) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ * Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_switchview.c
+ * \ingroup cmpnodes
+ */
+
+#include "BKE_context.h"
+#include "../node_composite_util.h"
+
+/* **************** SWITCH VIEW ******************** */
+static bNodeSocketTemplate cmp_node_switch_view_out[] = {
+ { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocket *ntreeCompositSwitchViewAddSocket(bNodeTree *ntree, bNode *node, const char *name)
+{
+ bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
+ return sock;
+}
+
+static void cmp_node_switch_view_sanitycheck(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+
+ if (!BLI_listbase_is_empty(&node->inputs))
+ return;
+
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, "No View");
+ sock->flag |= SOCK_HIDDEN;
+}
+
+static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+ SceneRenderView *srv;
+ Scene *scene = (Scene *)node->id;
+
+ /* only update when called from the operator button */
+ if (node->update != NODE_UPDATE_OPERATOR)
+ return;
+
+ if (scene == NULL) {
+ nodeRemoveAllSockets(ntree, node);
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+ return;
+ }
+
+ /* remove the views that were removed */
+ sock = node->inputs.last;
+ while (sock) {
+ srv = BLI_findstring(&scene->r.views, sock->name, offsetof(SceneRenderView, name));
+
+ if (srv == NULL) {
+ bNodeSocket *sock_del = sock;
+ sock = sock->prev;
+ nodeRemoveSocket(ntree, node, sock_del);
+ }
+ else {
+ if (srv->viewflag & SCE_VIEW_DISABLE)
+ sock->flag |= SOCK_HIDDEN;
+ else
+ sock->flag &= ~SOCK_HIDDEN;
+
+ sock = sock->prev;
+ }
+ }
+
+ /* add the new views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ sock = BLI_findstring(&node->inputs, srv->name, offsetof(bNodeSocket, name));
+
+ if (sock == NULL)
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
+
+ if (srv->viewflag & SCE_VIEW_DISABLE)
+ sock->flag |= SOCK_HIDDEN;
+ else
+ sock->flag &= ~SOCK_HIDDEN;
+ }
+
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+}
+
+static void init_switch_view(const bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ bNodeTree *ntree = ptr->id.data;
+ bNode *node = ptr->data;
+ SceneRenderView *srv;
+ bNodeSocket *sock;
+ int nr;
+
+ /* store scene for updates */
+ node->id = (ID *)scene;
+
+ if (scene) {
+ RenderData *rd = &scene->r;
+
+ for (nr = 0, srv = rd->views.first; srv; srv = srv->next, nr++) {
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
+
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ sock->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+}
+
+/* custom1 = mix type */
+void register_node_type_cmp_switch_view(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, NULL, cmp_node_switch_view_out);
+
+ ntype.initfunc_api = init_switch_view;
+
+ node_type_update(&ntype, cmp_node_switch_view_update, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 0e250dc3aa4..c397af97783 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -50,6 +50,10 @@
#include "node_util.h"
#include "NOD_common.h"
+enum {
+ REFINE_FORWARD = 1 << 0,
+ REFINE_BACKWARD = 1 << 1,
+};
/**** Group ****/
@@ -251,7 +255,7 @@ void register_node_type_reroute(void)
nodeRegisterType(ntype);
}
-static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node)
+static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, int flag)
{
bNodeSocket *input = node->inputs.first;
bNodeSocket *output = node->outputs.first;
@@ -275,11 +279,14 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node)
if (nodeLinkIsHidden(link))
continue;
- if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done)
- node_reroute_inherit_type_recursive(ntree, fromnode);
-
- if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done)
- node_reroute_inherit_type_recursive(ntree, tonode);
+ if (flag & REFINE_FORWARD) {
+ if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done)
+ node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD);
+ }
+ if (flag & REFINE_BACKWARD) {
+ if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done)
+ node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD);
+ }
}
/* determine socket type from unambiguous input/output connection if possible */
@@ -329,7 +336,7 @@ void ntree_update_reroute_nodes(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next)
if (node->type == NODE_REROUTE && !node->done)
- node_reroute_inherit_type_recursive(ntree, node);
+ node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD);
}
static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index f18ee1d649f..cd2c6f68726 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -69,7 +69,8 @@ static int shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
return (scene->r.engine[0] == '\0' ||
STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER) ||
STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME) ||
- STREQ(scene->r.engine, RE_engine_id_CYCLES));
+ STREQ(scene->r.engine, RE_engine_id_CYCLES) ||
+ !BKE_scene_use_shading_nodes_custom(scene));
}
static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index b9c94fc3aee..8dda7b0859b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -51,8 +51,8 @@ static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[3].link)
- in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ if (!in[4].link)
+ in[4].link = GPU_builtin(GPU_VIEW_NORMAL);
return GPU_stack_link(mat, "node_bsdf_anisotropic", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index de152ee45d1..3146454f26d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -47,7 +47,10 @@ static bNodeSocketTemplate sh_node_bump_out[] = {
static int gpu_shader_bump(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ if (!in[3].link)
+ in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+
+ return GPU_stack_link(mat, "node_bump", in, out);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index cff4a039602..2af6e19565b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -71,7 +71,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo
static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_tex_mapping(TEXMAP_TYPE_POINT);
+ node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
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 a862c621248..d1905246fd4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -30,10 +30,10 @@
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_object_info_out[] = {
- { SOCK_VECTOR, 0, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
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 f75f6a654d1..569eaf5ff9b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -51,8 +51,8 @@ static bNodeSocketTemplate sh_node_tex_brick_out[] = {
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->offset = 0.5f;
tex->squash = 1.0f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index 30e51c7cb7d..b7498df1706 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -46,8 +46,8 @@ static bNodeSocketTemplate sh_node_tex_checker_out[] = {
static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexChecker *tex = MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
node->storage = tex;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 8d6a77455bb..2b43667a009 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -42,8 +42,8 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = {
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
tex->iuser.frames = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index e11591ab5ce..24916e8f013 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -43,8 +43,8 @@ static bNodeSocketTemplate sh_node_tex_gradient_out[] = {
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexGradient *tex = MEM_callocN(sizeof(NodeTexGradient), "NodeTexGradient");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 62db5b70891..f87e792399b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -43,8 +43,8 @@ static bNodeSocketTemplate sh_node_tex_image_out[] = {
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index de2daeb8ee1..80904e376bc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -45,8 +45,8 @@ static bNodeSocketTemplate sh_node_tex_magic_out[] = {
static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMagic *tex = MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->depth = 2;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 75566773ea2..825ba7eb3c1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -49,8 +49,8 @@ static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMusgrave *tex = MEM_callocN(sizeof(NodeTexMusgrave), "NodeTexMusgrave");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 601a31dff00..d806140694e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -46,8 +46,8 @@ static bNodeSocketTemplate sh_node_tex_noise_out[] = {
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
node->storage = tex;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
index 51cca0df851..495c78ca929 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
@@ -42,8 +42,8 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = {
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
tex->sun_direction[1] = 0.0f;
tex->sun_direction[2] = 1.0f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index 5eba5f3f59d..88596a4a72f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -44,8 +44,8 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->coloring = SHD_VORONOI_INTENSITY;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index ef79aac0d32..100510641e8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -47,8 +47,8 @@ static bNodeSocketTemplate sh_node_tex_wave_out[] = {
static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexWave *tex = MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->wave_type = SHD_WAVE_BANDS;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index fa5d9b43ee7..72942cce9c5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -31,6 +31,7 @@
#include "node_shader_util.h"
+#include "IMB_colormanagement.h"
/* **************** VALTORGB ******************** */
static bNodeSocketTemplate sh_node_valtorgb_in[] = {
@@ -106,7 +107,7 @@ static void node_shader_exec_rgbtobw(void *UNUSED(data), int UNUSED(thread), bNo
float col[3];
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
- out[0]->vec[0] = rgb_to_bw(col);
+ out[0]->vec[0] = IMB_colormanagement_get_luminance(col);
}
static int gpu_shader_rgbtobw(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 79923c5f7d5..d716c2565c7 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -336,7 +336,7 @@ int ntreeTexExecTree(
data.osatex = osatex;
data.target = texres;
data.do_preview = preview;
- data.do_manage = (shi) ? shi->do_manage : 0;
+ data.do_manage = (shi) ? shi->do_manage : true;
data.thread = thread;
data.which_output = which_output;
data.cfra = cfra;
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index eb81bcd6949..2c5ecfdae0d 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -67,8 +67,6 @@
#include "node_util.h"
#include "NOD_texture.h"
-#include "NOD_texture.h"
-
#include "BLF_translation.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index b49ec1fd503..0be5f875a23 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -286,7 +286,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
Tex *tex = MEM_callocN(sizeof(Tex), "Tex");
node->storage = tex;
- default_tex(tex);
+ BKE_texture_default(tex);
tex->type = node->type - TEX_NODE_PROC;
if (tex->type == TEX_WOOD)
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 7f8adab2da5..a49d82d27a9 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -32,6 +32,7 @@
#include "node_texture_util.h"
#include "NOD_texture.h"
+#include "IMB_colormanagement.h"
/* **************** VALTORGB ******************** */
static bNodeSocketTemplate valtorgb_in[] = {
@@ -91,7 +92,7 @@ static void rgbtobw_valuefn(float *out, TexParams *p, bNode *UNUSED(node), bNode
{
float cin[4];
tex_input_rgba(cin, in[0], p, thread);
- *out = rgb_to_bw(cin);
+ *out = IMB_colormanagement_get_luminance(cin);
}
static void rgbtobw_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
index c189dea28a4..de5fdd2b81d 100644
--- a/source/blender/physics/BPH_mass_spring.h
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -25,6 +25,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file blender/physics/BPH_mass_spring.h
+ * \ingroup bph
+ */
+
#ifndef __BPH_MASS_SPRING_H__
#define __BPH_MASS_SPRING_H__
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index e0ca945eaf7..ff211e7906a 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -140,7 +140,7 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
- float margin_distance = collpair->distance - epsilon2;
+ float margin_distance = (float)collpair->distance - epsilon2;
float mag_v_rel;
zero_v3(r_impulse);
@@ -859,7 +859,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
Implicit_Data *id = cloth->implicit;
ClothVertex *verts = cloth->verts;
int numverts = cloth->numverts;
- const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;;
+ const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
bool do_extra_solve;
int i;
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
index cd3bd5ee45d..e4a4f306aeb 100644
--- a/source/blender/physics/intern/eigen_utils.h
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -28,7 +28,7 @@
#ifndef __EIGEN_UTILS_H__
#define __EIGEN_UTILS_H__
-/** \file eigen_utils.h
+/** \file blender/physics/intern/eigen_utils.h
* \ingroup bph
*/
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index b07af1d201c..d79cf7d8c31 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -594,7 +594,7 @@ BLI_INLINE float hair_volume_density_divergence(float density, float target_dens
return 0.0f;
}
-bool BPH_hair_volume_solve_divergence(HairGrid *grid, float dt, float target_density, float target_strength)
+bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target_density, float target_strength)
{
const float flowfac = grid->cellsize;
const float inv_flowfac = 1.0f / grid->cellsize;
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index d286d3df1a5..dba1cd11ae0 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -59,7 +59,6 @@ extern "C" {
//#define IMPLICIT_ENABLE_EIGEN_DEBUG
struct Implicit_Data;
-struct ImplicitSolverInput;
typedef struct ImplicitSolverResult {
int status;
@@ -133,7 +132,6 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const
struct HairGrid;
-struct Object;
struct VoxelData;
#define MAX_HAIR_GRID_RES 256
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index a5cf0b94c62..815beebb159 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -86,6 +86,7 @@ void BPY_driver_reset(void);
float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
int BPY_button_exec(struct bContext *C, const char *expr, double *value, const bool verbose);
+int BPY_string_exec_ex(struct bContext *C, const char *expr, bool use_eval);
int BPY_string_exec(struct bContext *C, const char *expr);
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index bc14e1ac3a6..f74737ba8f4 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -108,7 +108,7 @@ PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc,
" :type mesh: :class:`bpy.types.Mesh`\n"
" :arg tessface: Option to recalculate n-gon tessellation.\n"
" :type tessface: boolean\n"
-" :arg destructive: Use when grometry has been added or removed.\n"
+" :arg destructive: Use when geometry has been added or removed.\n"
" :type destructive: boolean\n"
);
static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 84c1031a24a..a4c057acac2 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -69,9 +69,10 @@ static int bpy_bm_op_as_py_error(BMesh *bm)
* \param htype Test \a value matches this type.
* \param descr Description text.
*/
-static int bpy_slot_from_py_elem_check(BPy_BMElem *value, BMesh *bm, const char htype,
- /* for error messages */
- const char *opname, const char *slot_name, const char *descr)
+static int bpy_slot_from_py_elem_check(
+ BPy_BMElem *value, BMesh *bm, const char htype,
+ /* for error messages */
+ const char *opname, const char *slot_name, const char *descr)
{
if (!BPy_BMElem_Check(value) ||
!(value->ele->head.htype & htype))
@@ -107,10 +108,11 @@ static int bpy_slot_from_py_elem_check(BPy_BMElem *value, BMesh *bm, const char
* \param htype_bmo The type(s) supported by the target slot.
* \param descr Description text.
*/
-static int bpy_slot_from_py_elemseq_check(BPy_BMGeneric *value, BMesh *bm,
- const char htype_py, const char htype_bmo,
- /* for error messages */
- const char *opname, const char *slot_name, const char *descr)
+static int bpy_slot_from_py_elemseq_check(
+ BPy_BMGeneric *value, BMesh *bm,
+ const char htype_py, const char htype_bmo,
+ /* for error messages */
+ const char *opname, const char *slot_name, const char *descr)
{
if (value->bm == NULL) {
PyErr_Format(PyExc_TypeError,
@@ -142,9 +144,10 @@ static int bpy_slot_from_py_elemseq_check(BPy_BMGeneric *value, BMesh *bm,
/**
* Use for giving py args to an operator.
*/
-static int bpy_slot_from_py(BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObject *value,
- /* the are just for exception messages */
- const char *opname, const char *slot_name)
+static int bpy_slot_from_py(
+ BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObject *value,
+ /* the are just for exception messages */
+ const char *opname, const char *slot_name)
{
switch (slot->slot_type) {
case BMO_OP_SLOT_BOOL:
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 20ee872b3be..f63381d7a7d 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -79,6 +79,8 @@ PyC_FlagSet bpy_bm_htype_all_flags[] = {
{0, NULL}
};
+#define BPY_BM_HFLAG_ALL_STR "('SELECT', 'HIDE', 'SEAM', 'SMOOTH', 'TAG')"
+
PyC_FlagSet bpy_bm_hflag_all_flags[] = {
{BM_ELEM_SELECT, "SELECT"},
{BM_ELEM_HIDDEN, "HIDE"},
@@ -1128,7 +1130,7 @@ PyDoc_STRVAR(bpy_bmesh_transform_doc,
"\n"
" :arg matrix: transform matrix.\n"
" :type matrix: 4x4 :class:`mathutils.Matrix`\n"
-" :arg filter: set of values in ('SELECT', 'HIDE', 'SEAM', 'SMOOTH', 'TAG').\n"
+" :arg filter: set of values in " BPY_BM_HFLAG_ALL_STR ".\n"
" :type filter: set\n"
);
static PyObject *bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject *kw)
@@ -3251,17 +3253,17 @@ static PyObject *bpy_bmloop_repr(BPy_BMLoop *self)
/* Types
* ===== */
-PyTypeObject BPy_BMesh_Type = {{{0}}};
-PyTypeObject BPy_BMVert_Type = {{{0}}};
-PyTypeObject BPy_BMEdge_Type = {{{0}}};
-PyTypeObject BPy_BMFace_Type = {{{0}}};
-PyTypeObject BPy_BMLoop_Type = {{{0}}};
-PyTypeObject BPy_BMElemSeq_Type = {{{0}}};
-PyTypeObject BPy_BMVertSeq_Type = {{{0}}};
-PyTypeObject BPy_BMEdgeSeq_Type = {{{0}}};
-PyTypeObject BPy_BMFaceSeq_Type = {{{0}}};
-PyTypeObject BPy_BMLoopSeq_Type = {{{0}}};
-PyTypeObject BPy_BMIter_Type = {{{0}}};
+PyTypeObject BPy_BMesh_Type;
+PyTypeObject BPy_BMVert_Type;
+PyTypeObject BPy_BMEdge_Type;
+PyTypeObject BPy_BMFace_Type;
+PyTypeObject BPy_BMLoop_Type;
+PyTypeObject BPy_BMElemSeq_Type;
+PyTypeObject BPy_BMVertSeq_Type;
+PyTypeObject BPy_BMEdgeSeq_Type;
+PyTypeObject BPy_BMFaceSeq_Type;
+PyTypeObject BPy_BMLoopSeq_Type;
+PyTypeObject BPy_BMIter_Type;
@@ -3757,10 +3759,11 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
*
* The 'bm_r' value is assigned when empty, and used when set.
*/
-void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check, const bool do_bm_check,
- const char *error_prefix)
+void *BPy_BMElem_PySeq_As_Array(
+ BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+ const char htype,
+ const bool do_unique_check, const bool do_bm_check,
+ const char *error_prefix)
{
BMesh *bm = (r_bm && *r_bm) ? *r_bm : NULL;
PyObject *seq_fast;
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 66059a642d1..630afcb32c0 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -158,10 +158,11 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele); /* just checks type and creates v/e/f/l */
-void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check, const bool do_bm_check,
- const char *error_prefix);
+void *BPy_BMElem_PySeq_As_Array(
+ BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+ const char htype,
+ const bool do_unique_check, const bool do_bm_check,
+ const char *error_prefix);
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len);
PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index bfcd91ac72d..3adf37f78f0 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -116,6 +116,9 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc,
PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc,
"Accessor for skin layer.\n\ntype: :class:`BMLayerCollection`"
);
+PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc,
+"Accessor for paint mask layer.\n\ntype: :class:`BMLayerCollection`"
+);
#ifdef WITH_FREESTYLE
PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_edge_doc,
"Accessor for Freestyle edge layer.\n\ntype: :class:`BMLayerCollection`"
@@ -196,6 +199,7 @@ static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = {
{(char *)"shape", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__shape_doc, (void *)CD_SHAPEKEY},
{(char *)"bevel_weight", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__bevel_weight_doc, (void *)CD_BWEIGHT},
{(char *)"skin", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__skin_doc, (void *)CD_MVERT_SKIN},
+ {(char *)"paint_mask", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__paint_mask_doc, (void *)CD_PAINT_MASK},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -787,12 +791,12 @@ PyDoc_STRVAR(bpy_bmlayeritem_type_doc,
);
-PyTypeObject BPy_BMLayerAccessVert_Type = {{{0}}}; /* bm.verts.layers */
-PyTypeObject BPy_BMLayerAccessEdge_Type = {{{0}}}; /* bm.edges.layers */
-PyTypeObject BPy_BMLayerAccessFace_Type = {{{0}}}; /* bm.faces.layers */
-PyTypeObject BPy_BMLayerAccessLoop_Type = {{{0}}}; /* bm.loops.layers */
-PyTypeObject BPy_BMLayerCollection_Type = {{{0}}}; /* bm.loops.layers.uv */
-PyTypeObject BPy_BMLayerItem_Type = {{{0}}}; /* bm.loops.layers.uv["UVMap"] */
+PyTypeObject BPy_BMLayerAccessVert_Type; /* bm.verts.layers */
+PyTypeObject BPy_BMLayerAccessEdge_Type; /* bm.edges.layers */
+PyTypeObject BPy_BMLayerAccessFace_Type; /* bm.faces.layers */
+PyTypeObject BPy_BMLayerAccessLoop_Type; /* bm.loops.layers */
+PyTypeObject BPy_BMLayerCollection_Type; /* bm.loops.layers.uv */
+PyTypeObject BPy_BMLayerItem_Type; /* bm.loops.layers.uv["UVMap"] */
PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
@@ -984,6 +988,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
break;
}
case CD_PROP_FLT:
+ case CD_PAINT_MASK:
{
ret = PyFloat_FromDouble(*(float *)value);
break;
@@ -1061,6 +1066,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
break;
}
case CD_PROP_FLT:
+ case CD_PAINT_MASK:
{
float tmp_val = PyFloat_AsDouble(py_value);
if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index 94f38ffdec7..92c11a03433 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -99,7 +99,7 @@ static PyGetSetDef bpy_bmtexpoly_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-static PyTypeObject BPy_BMTexPoly_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+static PyTypeObject BPy_BMTexPoly_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmtexpoly(void)
{
@@ -212,7 +212,7 @@ static PyGetSetDef bpy_bmloopuv_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-PyTypeObject BPy_BMLoopUV_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+PyTypeObject BPy_BMLoopUV_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmloopuv(void)
{
@@ -321,7 +321,7 @@ static PyGetSetDef bpy_bmvertskin_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-static PyTypeObject BPy_BMVertSkin_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+static PyTypeObject BPy_BMVertSkin_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmvertskin(void)
{
@@ -750,7 +750,7 @@ static struct PyMethodDef bpy_bmdeformvert_methods[] = {
{NULL, NULL, 0, NULL}
};
-PyTypeObject BPy_BMDeformVert_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+PyTypeObject BPy_BMDeformVert_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmdvert(void)
{
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index 7b792e9f08e..a2dceb2a877 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -342,8 +342,8 @@ static PyObject *bpy_bmeditseliter_next(BPy_BMEditSelIter *self)
}
}
-PyTypeObject BPy_BMEditSelSeq_Type = {{{0}}};
-PyTypeObject BPy_BMEditSelIter_Type = {{{0}}};
+PyTypeObject BPy_BMEditSelSeq_Type;
+PyTypeObject BPy_BMEditSelIter_Type;
PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm)
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 2e32a571e3c..b7890926a85 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -84,7 +84,7 @@ static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObjec
return NULL;
}
- if (BM_vert_edge_count(py_vert->v) > 2) {
+ if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
return NULL;
@@ -150,7 +150,7 @@ static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObje
return NULL;
}
- if (BM_vert_edge_count(py_vert->v) > 2) {
+ if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
return NULL;
@@ -253,7 +253,7 @@ static PyObject *bpy_bm_utils_vert_splice(PyObject *UNUSED(self), PyObject *args
}
/* should always succeed */
- ok = BM_vert_splice(bm, py_vert->v, py_vert_target->v);
+ ok = BM_vert_splice(bm, py_vert_target->v, py_vert->v);
BLI_assert(ok == true);
UNUSED_VARS_NDEBUG(ok);
@@ -307,7 +307,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar
return NULL;
}
- BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len);
+ BM_vert_separate(bm, py_vert->v, edge_array, edge_array_len, false, &elem, &elem_len);
/* return collected verts */
ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len);
MEM_freeN(elem);
@@ -670,7 +670,7 @@ PyDoc_STRVAR(bpy_bm_utils_face_vert_separate_doc,
" :type face: :class:`bmesh.types.BMFace`\n"
" :arg vert: A vertex in the face to separate.\n"
" :type vert: :class:`bmesh.types.BMVert`\n"
-" :return vert: The newly created vertex or None of failure.\n"
+" :return vert: The newly created vertex or None on failure.\n"
" :rtype vert: :class:`bmesh.types.BMVert`\n"
"\n"
" .. note::\n"
@@ -749,9 +749,9 @@ PyDoc_STRVAR(bpy_bm_utils_loop_separate_doc,
"\n"
" Rip a vertex in a face away and add a new vertex.\n"
"\n"
-" :arg loop: The to separate.\n"
-" :type loop: :class:`bmesh.types.BMFace`\n"
-" :return vert: The newly created vertex or None of failure.\n"
+" :arg loop: The loop to separate.\n"
+" :type loop: :class:`bmesh.types.BMLoop`\n"
+" :return vert: The newly created vertex or None on failure.\n"
" :rtype vert: :class:`bmesh.types.BMVert`\n"
);
static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *value)
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index ed1ac7ceed9..5364c3bbb9e 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -33,7 +33,7 @@
#include "BLI_utildefines.h"
-#include "../generic/python_utildefines.h"
+#include "python_utildefines.h"
PyDoc_STRVAR(py_blf_position_doc,
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 1f35572a483..30e0ccdb106 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -41,7 +41,7 @@
#include "py_capi_utils.h"
#endif
-#include "../generic/python_utildefines.h"
+#include "python_utildefines.h"
/*********************** ID Property Main Wrapper Stuff ***************/
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 92ac82508e5..1b72928b26e 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -37,7 +37,7 @@
#include "py_capi_utils.h"
-#include "../generic/python_utildefines.h"
+#include "python_utildefines.h"
/* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */
#include "BLI_string_utf8.h"
@@ -478,6 +478,34 @@ error_cleanup:
}
#endif
+PyObject *PyC_ExceptionBuffer_Simple(void)
+{
+ PyObject *string_io_buf;
+
+ PyObject *error_type, *error_value, *error_traceback;
+
+ if (!PyErr_Occurred())
+ return NULL;
+
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ if (error_value == NULL) {
+ return NULL;
+ }
+
+ string_io_buf = PyObject_Str(error_value);
+ /* Python does this too */
+ if (UNLIKELY(string_io_buf == NULL)) {
+ string_io_buf = PyUnicode_FromFormat(
+ "<unprintable %s object>", Py_TYPE(error_value)->tp_name);
+ }
+
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ PyErr_Print();
+ PyErr_Clear();
+ return string_io_buf;
+}
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 398d7da9179..ab630d1d203 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -32,6 +32,7 @@ void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
PyObject * PyC_ExceptionBuffer(void);
+PyObject * PyC_ExceptionBuffer_Simple(void);
PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject * PyC_FrozenSetFromStrings(const char **strings);
PyObject * PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 8296027f044..ed04152182e 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../blenloader
../../editors/include
../../gpu
+ ../../imbuf
../../makesdna
../../makesrna
../../windowmanager
@@ -69,6 +70,7 @@ set(SRC
bpy_rna_callback.c
bpy_traceback.c
bpy_util.c
+ bpy_utils_previews.c
bpy_utils_units.c
stubs.c
@@ -94,6 +96,7 @@ set(SRC
bpy_rna_callback.h
bpy_traceback.h
bpy_util.h
+ bpy_utils_previews.h
bpy_utils_units.h
../BPY_extern.h
)
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index ec3c017a7ed..9a5e488850e 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -48,6 +48,7 @@
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
+#include "bpy_utils_previews.h"
#include "bpy_utils_units.h"
#include "../generic/py_capi_utils.h"
@@ -330,6 +331,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "ops", BPY_operator_module());
PyModule_AddObject(mod, "app", BPY_app_struct());
PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
+ PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
/* bpy context */
RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index c8a4971847b..1cf0c44fd87 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -220,6 +220,33 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos
return 0;
}
+
+
+PyDoc_STRVAR(bpy_app_binary_path_python_doc,
+"String, the path to the python executable (read-only)"
+);
+static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure))
+{
+ /* refcount is held in BlenderAppType.tp_dict */
+ static PyObject *ret = NULL;
+
+ if (ret == NULL) {
+ /* only run once */
+ char fullpath[1024];
+ BKE_appdir_program_python_search(
+ fullpath, sizeof(fullpath),
+ PY_MAJOR_VERSION, PY_MINOR_VERSION);
+ ret = PyC_UnicodeFromByte(fullpath);
+ PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret);
+ }
+ else {
+ Py_INCREF(ret);
+ }
+
+ return ret;
+
+}
+
PyDoc_STRVAR(bpy_app_debug_value_doc,
"Int, number which can be set to non-zero values for testing purposes"
);
@@ -287,6 +314,9 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug_wm", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
{(char *)"debug_depsgraph", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH},
{(char *)"debug_simdata", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
+ {(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM},
+
+ {(char *)"binary_path_python", bpy_app_binary_path_python_get, NULL, (char *)bpy_app_binary_path_python_doc, NULL},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index 123b111f3cb..72133badbbb 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -47,8 +47,7 @@
#include "../generic/python_utildefines.h"
-typedef struct
-{
+typedef struct {
PyObject_HEAD
/* The string used to separate context from actual message in PY_TRANSLATE RNA props. */
const char *context_separator;
@@ -821,3 +820,12 @@ PyObject *BPY_app_translations_struct(void)
return ret;
}
+
+void BPY_app_translations_end(void)
+{
+ /* Incase the object remains in a module's namespace, see T44127. */
+#ifdef WITH_INTERNATIONAL
+ _clear_translations_cache();
+#endif
+}
+
diff --git a/source/blender/python/intern/bpy_app_translations.h b/source/blender/python/intern/bpy_app_translations.h
index 704307574d0..e04c2484ecc 100644
--- a/source/blender/python/intern/bpy_app_translations.h
+++ b/source/blender/python/intern/bpy_app_translations.h
@@ -28,5 +28,6 @@
#define __BPY_APP_TRANSLATIONS_H__
PyObject *BPY_app_translations_struct(void);
+void BPY_app_translations_end(void);
#endif /* __BPY_APP_TRANSLATIONS_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 5b4db89a41a..7e5ad00159e 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -61,6 +61,8 @@
#include "bpy_traceback.h"
#include "bpy_intern_string.h"
+#include "bpy_app_translations.h"
+
#include "DNA_text_types.h"
#include "BKE_appdir.h"
@@ -358,6 +360,9 @@ void BPY_python_end(void)
bpy_intern_string_exit();
+ /* bpy.app modules that need cleanup */
+ BPY_app_translations_end();
+
#ifndef WITH_PYTHON_MODULE
BPY_atexit_unregister(); /* without this we get recursive calls to WM_exit */
@@ -590,7 +595,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
if (error_ret) {
if (verbose) {
- BPy_errors_to_report(CTX_wm_reports(C));
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
}
else {
PyErr_Clear();
@@ -602,7 +607,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
return error_ret;
}
-int BPY_string_exec(bContext *C, const char *expr)
+int BPY_string_exec_ex(bContext *C, const char *expr, bool use_eval)
{
PyGILState_STATE gilstate;
PyObject *main_mod = NULL;
@@ -625,7 +630,7 @@ int BPY_string_exec(bContext *C, const char *expr)
bmain_back = bpy_import_main_get();
bpy_import_main_set(CTX_data_main(C));
- retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
+ retval = PyRun_String(expr, use_eval ? Py_eval_input : Py_file_input, py_dict, py_dict);
bpy_import_main_set(bmain_back);
@@ -645,6 +650,10 @@ int BPY_string_exec(bContext *C, const char *expr)
return error_ret;
}
+int BPY_string_exec(bContext *C, const char *expr)
+{
+ return BPY_string_exec_ex(C, expr, true);
+}
void BPY_modules_load_user(bContext *C)
{
@@ -779,7 +788,6 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
}
#ifdef WITH_PYTHON_MODULE
-#include "BLI_fileops.h"
/* TODO, reloading the module isn't functional at the moment. */
static void bpy_module_free(void *mod);
@@ -831,7 +839,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
static void dealloc_obj_dealloc(PyObject *self);
-static PyTypeObject dealloc_obj_Type = {{{0}}};
+static PyTypeObject dealloc_obj_Type;
/* use our own dealloc so we can free a property if we use one */
static void dealloc_obj_dealloc(PyObject *self)
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 8370aea4c99..b0fae243182 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -68,7 +68,8 @@ static EnumPropertyItem property_flag_items[] = {
{0, NULL, 0, NULL, NULL}};
#define BPY_PROPDEF_OPTIONS_DOC \
-" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'].\n" \
+" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \
+ "'TEXTEDIT_UPDATE'].\n" \
" :type options: set\n" \
static EnumPropertyItem property_flag_enum_items[] = {
@@ -1480,15 +1481,26 @@ static EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, PointerRNA *
EnumPropertyItem *eitems = NULL;
int err = 0;
- bpy_context_set(C, &gilstate);
+ if (C) {
+ bpy_context_set(C, &gilstate);
+ }
+ else {
+ gilstate = PyGILState_Ensure();
+ }
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
/* now get the context */
- PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
- Py_INCREF(bpy_context_module);
+ if (C) {
+ PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
+ Py_INCREF(bpy_context_module);
+ }
+ else {
+ PyTuple_SET_ITEM(args, 1, Py_None);
+ Py_INCREF(Py_None);
+ }
items = PyObject_CallObject(py_func, args);
@@ -1529,8 +1541,13 @@ static EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, PointerRNA *
eitems = DummyRNA_NULL_items;
}
+ if (C) {
+ bpy_context_clear(C, &gilstate);
+ }
+ else {
+ PyGILState_Release(gilstate);
+ }
- bpy_context_clear(C, &gilstate);
return eitems;
}
@@ -2617,7 +2634,7 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" Note the item is optional.\n"
" For dynamic values a callback can be passed which returns a list in\n"
" the same format as the static list.\n"
-" This function must take 2 arguments (self, context)\n"
+" This function must take 2 arguments (self, context), **context may be None**.\n"
" WARNING: There is a known bug with using a callback,\n"
" Python must keep a reference to the strings returned or Blender will crash.\n"
" :type items: sequence of string tuples or a function\n"
@@ -2965,9 +2982,10 @@ static struct PyMethodDef props_methods[] = {
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
- "This module defines properties to extend blenders internal data, the result of these functions"
- " is used to assign properties to classes registered with blender and can't be used directly.\n"
- ".. warning:: All parameters to these functions must be passed as keywords.",
+ "This module defines properties to extend Blender's internal data. The result of these functions"
+ " is used to assign properties to classes registered with Blender and can't be used directly.\n"
+ "\n"
+ ".. warning:: All parameters to these functions must be passed as keywords.\n",
-1, /* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index fadc50e3317..d15e3b36ced 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -53,10 +53,6 @@
#include "bpy_intern_string.h"
#ifdef USE_PYRNA_INVALIDATE_WEAKREF
-# include "MEM_guardedalloc.h"
-#endif
-
-#ifdef USE_PYRNA_INVALIDATE_WEAKREF
# include "BLI_ghash.h"
#endif
@@ -177,7 +173,7 @@ static GHash *id_weakref_pool_get(ID *id)
if (weakinfo_hash == NULL) {
/* we're using a ghash as a set, could use libHX's HXMAP_SINGULAR but would be an extra dep. */
weakinfo_hash = BLI_ghash_ptr_new("rna_id");
- BLI_ghash_insert(id_weakref_pool, (void *)id, weakinfo_hash);
+ BLI_ghash_insert(id_weakref_pool, id, weakinfo_hash);
}
return weakinfo_hash;
@@ -203,7 +199,7 @@ static void id_weakref_pool_add(ID *id, BPy_DummyPointerRNA *pyrna)
Py_DECREF(weakref_cb_py); /* function owned by the weakref now */
/* important to add at the end, since first removal looks at the end */
- BLI_ghash_insert(weakinfo_hash, (void *)weakref, id); /* using a hash table as a set, all 'id's are the same */
+ BLI_ghash_insert(weakinfo_hash, weakref, id); /* using a hash table as a set, all 'id's are the same */
/* weakinfo_hash owns the weakref */
}
@@ -1830,25 +1826,23 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
RNA_property_pointer_set(ptr, prop, param->ptr);
}
else {
+ raise_error = true;
+ }
+ }
+
+ if (raise_error) {
+ if (pyrna_struct_validity_check(param) == -1) {
+ /* error set */
+ }
+ else {
PointerRNA tmp;
RNA_pointer_create(NULL, ptr_type, NULL, &tmp);
PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type. not %.200s",
+ "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
error_prefix, RNA_struct_identifier(ptr->type),
RNA_property_identifier(prop), RNA_struct_identifier(tmp.type),
RNA_struct_identifier(param->ptr.type));
- Py_XDECREF(value_new); return -1;
}
- }
-
- if (raise_error) {
- PointerRNA tmp;
- RNA_pointer_create(NULL, ptr_type, NULL, &tmp);
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
- error_prefix, RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop), RNA_struct_identifier(tmp.type),
- RNA_struct_identifier(param->ptr.type));
Py_XDECREF(value_new); return -1;
}
}
@@ -5241,7 +5235,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
good_args_str = BLI_dynstr_get_cstring(good_args);
PyErr_Format(PyExc_TypeError,
- "%.200s.%.200s(): was called with invalid keyword arguments(s) (%s), expected (%s)",
+ "%.200s.%.200s(): was called with invalid keyword argument(s) (%s), expected (%s)",
RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func),
bad_args_str, good_args_str);
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index 93183a4f320..e876adfa58e 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -82,14 +82,9 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
}
-short BPy_errors_to_report(ReportList *reports)
+bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const bool use_location)
{
PyObject *pystring;
- PyObject *pystring_format = NULL; /* workaround, see below */
- const char *cstring;
-
- const char *filename;
- int lineno;
if (!PyErr_Occurred())
return 1;
@@ -101,31 +96,56 @@ short BPy_errors_to_report(ReportList *reports)
return 1;
}
- pystring = PyC_ExceptionBuffer();
+ if (use_full) {
+ pystring = PyC_ExceptionBuffer();
+ }
+ else {
+ pystring = PyC_ExceptionBuffer_Simple();
+ }
if (pystring == NULL) {
BKE_report(reports, RPT_ERROR, "Unknown py-exception, could not convert");
return 0;
}
-
- PyC_FileAndNum(&filename, &lineno);
- if (filename == NULL)
- filename = "<unknown location>";
-
- cstring = _PyUnicode_AsString(pystring);
+
+ if (use_location) {
+ const char *filename;
+ int lineno;
+
+ PyObject *pystring_format; /* workaround, see below */
+ const char *cstring;
+
+ PyC_FileAndNum(&filename, &lineno);
+ if (filename == NULL) {
+ filename = "<unknown location>";
+ }
#if 0 /* ARG!. workaround for a bug in blenders use of vsnprintf */
- BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", cstring, filename, lineno);
+ BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", _PyUnicode_AsString(pystring), filename, lineno);
#else
- pystring_format = PyUnicode_FromFormat(TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
- cstring = _PyUnicode_AsString(pystring_format);
- BKE_report(reports, RPT_ERROR, cstring);
+ pystring_format = PyUnicode_FromFormat(
+ TIP_("%s\nlocation: %s:%d\n"),
+ _PyUnicode_AsString(pystring), filename, lineno);
+
+ cstring = _PyUnicode_AsString(pystring_format);
+ BKE_report(reports, RPT_ERROR, cstring);
+
+ /* not exactly needed. just for testing */
+ fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
+
+ Py_DECREF(pystring_format); /* workaround */
#endif
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(pystring));
+ }
- /* not exactly needed. just for testing */
- fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
Py_DECREF(pystring);
- Py_DECREF(pystring_format); /* workaround */
return 1;
}
+
+bool BPy_errors_to_report(ReportList *reports)
+{
+ return BPy_errors_to_report_ex(reports, true, true);
+} \ No newline at end of file
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index d19696aa230..1ae00a7fb02 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -40,7 +40,8 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item);
/* error reporting */
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
-short BPy_errors_to_report(struct ReportList *reports);
+bool BPy_errors_to_report_ex(struct ReportList *reports, const bool use_full, const bool use_location);
+bool BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
struct bContext *BPy_GetContext(void);
diff --git a/source/blender/python/intern/bpy_utils_previews.c b/source/blender/python/intern/bpy_utils_previews.c
new file mode 100644
index 00000000000..fed7c7210de
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_previews.c
@@ -0,0 +1,188 @@
+/*
+ * ***** 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): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_utils_previews.c
+ * \ingroup pythonintern
+ *
+ * This file defines a singleton py object accessed via 'bpy.utils.previews',
+ * which exposes low-level API for custom previews/icons.
+ * It is replaced in final API by an higher-level python wrapper, that handles previews by addon,
+ * and automatically release them on deletion.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_types.h"
+#include "RNA_access.h"
+
+#include "BPY_extern.h"
+#include "bpy_utils_previews.h"
+#include "bpy_rna.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
+#include "BKE_icons.h"
+
+#include "DNA_ID.h"
+
+#include "../generic/python_utildefines.h"
+
+#define STR_SOURCE_TYPES "'IMAGE', 'MOVIE', 'BLEND', 'FONT'"
+
+PyDoc_STRVAR(bpy_utils_previews_new_doc,
+".. method:: new(name)\n"
+"\n"
+" Generate a new empty preview, or return existing one matching ``name``.\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+" :return: The Preview matching given name, or a new empty one.\n"
+" :rtype: :class:`bpy.types.ImagePreview`\n"
+);
+static PyObject *bpy_utils_previews_new(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name;
+ PreviewImage *prv;
+ PointerRNA ptr;
+
+ if (!PyArg_ParseTuple(args, "s:new", &name)) {
+ return NULL;
+ }
+
+ prv = BKE_previewimg_cached_ensure(name);
+ RNA_pointer_create(NULL, &RNA_ImagePreview, prv, &ptr);
+
+ return pyrna_struct_CreatePyObject(&ptr);
+}
+
+PyDoc_STRVAR(bpy_utils_previews_load_doc,
+".. method:: load(name, filepath, filetype, force_reload=False)\n"
+"\n"
+" Generate a new preview from given file path, or return existing one matching ``name``.\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+" :arg filepath: The file path to generate the preview from.\n"
+" :type filepath: string\n"
+" :arg filetype: The type of file, needed to generate the preview in [" STR_SOURCE_TYPES "].\n"
+" :type filetype: string\n"
+" :arg force_reload: If True, force running thumbnail manager even if preview already exists in cache.\n"
+" :type force_reload: bool\n"
+" :return: The Preview matching given name, or a new empty one.\n"
+" :rtype: :class:`bpy.types.ImagePreview`\n"
+);
+static PyObject *bpy_utils_previews_load(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name, *path, *path_type_s;
+ int path_type, force_reload = false;
+
+ PreviewImage *prv;
+ PointerRNA ptr;
+
+ if (!PyArg_ParseTuple( args, "sss|p:load", &name, &path, &path_type_s, &force_reload)) {
+ return NULL;
+ }
+
+ if (STREQ(path_type_s, "IMAGE")) {
+ path_type = THB_SOURCE_IMAGE;
+ }
+ else if (STREQ(path_type_s, "MOVIE")) {
+ path_type = THB_SOURCE_MOVIE;
+ }
+ else if (STREQ(path_type_s, "BLEND")) {
+ path_type = THB_SOURCE_BLEND;
+ }
+ else if (STREQ(path_type_s, "FONT")) {
+ path_type = THB_SOURCE_FONT;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "load: invalid '%s' filetype, only [" STR_SOURCE_TYPES "] "
+ "are supported", path_type_s);
+ return NULL;
+ }
+
+ prv = BKE_previewimg_cached_thumbnail_read(name, path, path_type, force_reload);
+ RNA_pointer_create(NULL, &RNA_ImagePreview, prv, &ptr);
+
+ return pyrna_struct_CreatePyObject(&ptr);
+}
+
+PyDoc_STRVAR(bpy_utils_previews_release_doc,
+".. method:: release(name)\n"
+"\n"
+" Release (free) a previously created preview.\n"
+"\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+);
+static PyObject *bpy_utils_previews_release(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name;
+
+ if (!PyArg_ParseTuple(args, "s:release", &name)) {
+ return NULL;
+ }
+
+ BKE_previewimg_cached_release(name);
+
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef bpy_utils_previews_methods[] = {
+ /* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */
+ {"new", (PyCFunction)bpy_utils_previews_new, METH_VARARGS, bpy_utils_previews_new_doc},
+ {"load", (PyCFunction)bpy_utils_previews_load, METH_VARARGS, bpy_utils_previews_load_doc},
+ {"release", (PyCFunction)bpy_utils_previews_release, METH_VARARGS, bpy_utils_previews_release_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpy_utils_previews_doc,
+"This object contains basic static methods to handle cached (non-ID) previews in Blender\n"
+"(low-level API, not exposed to final users)."
+);
+static struct PyModuleDef bpy_utils_previews_module = {
+ PyModuleDef_HEAD_INIT,
+ "bpy._utils_previews",
+ bpy_utils_previews_doc,
+ 0,
+ bpy_utils_previews_methods,
+ NULL, NULL, NULL, NULL
+};
+
+
+PyObject *BPY_utils_previews_module(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&bpy_utils_previews_module);
+
+ return submodule;
+}
diff --git a/source/blender/python/intern/bpy_utils_previews.h b/source/blender/python/intern/bpy_utils_previews.h
new file mode 100644
index 00000000000..3d7ade04b9f
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_previews.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.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_utils_previews.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_UTILS_PREVIEWS_H__
+#define __BPY_UTILS_PREVIEWS_H__
+
+PyObject *BPY_utils_previews_module(void);
+
+#endif /* __BPY_UTILS_PREVIEWS_H__ */
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index a6df8f54cc3..d40e7e070ac 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -155,18 +155,18 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
}
PyDoc_STRVAR(bpyunits_to_value_doc,
-".. method:: to_value(unit_system, unit_category, str_input, [str_ref_unit=None])\n"
+".. method:: to_value(unit_system, unit_category, str_input, str_ref_unit=None)\n"
"\n"
" Convert a given input string into a float value.\n"
"\n"
" :arg unit_system: The unit system, from :attr:`bpy.utils.units.systems`.\n"
" :type unit_system: string\n"
-" :arg unit_category: The category of data we are converting (length, area, rotation, etc.), "
+" :arg unit_category: The category of data we are converting (length, area, rotation, etc.),\n"
" from :attr:`bpy.utils.units.categories`.\n"
" :type unit_category: string\n"
" :arg str_input: The string to convert to a float value.\n"
" :type str_input: string\n"
-" :arg str_ref_unit: A reference string from which to extract a default unit, if none is found in :arg:`str_input`.\n"
+" :arg str_ref_unit: A reference string from which to extract a default unit, if none is found in ``str_input``.\n"
" :type str_ref_unit: string or None\n"
" :return: The converted/interpreted value.\n"
" :rtype: float\n"
@@ -221,13 +221,13 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
}
PyDoc_STRVAR(bpyunits_to_string_doc,
-".. method:: to_string(unit_system, unit_category, value, [precision=3, [split_unit=False, [compatible_unit=False]]])\n"
+".. method:: to_string(unit_system, unit_category, value, precision=3, split_unit=False, compatible_unit=False)\n"
"\n"
" Convert a given input float value into a string with units.\n"
"\n"
" :arg unit_system: The unit system, from :attr:`bpy.utils.units.systems`.\n"
" :type unit_system: string\n"
-" :arg unit_category: The category of data we are converting (length, area, rotation, etc.), "
+" :arg unit_category: The category of data we are converting (length, area, rotation, etc.),\n"
" from :attr:`bpy.utils.units.categories`.\n"
" :type unit_category: string\n"
" :arg value: The value to convert to a string.\n"
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index e4580e8035b..f933c02390c 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -79,7 +79,17 @@ static PyObject *PyInit_gpu(void)
if (m == NULL)
return NULL;
+ /* device constant groups */
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_OBJECT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_SAMPLER);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MIST);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_WORLD);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MAT);
+
/* device constants */
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT);
@@ -92,9 +102,30 @@ static PyObject *PyInit_gpu(void)
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB);
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I);
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F);
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 7b51b08451b..361fbc8a005 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -110,7 +110,7 @@ Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
return x;
}
-/* helper functionm returns length of the 'value', -1 on error */
+/* helper function returns length of the 'value', -1 on error */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
const int flag = array_max;
@@ -535,7 +535,7 @@ PyObject *BaseMathObject_freeze(BaseMathObject *self)
self->flag |= BASE_MATH_FLAG_IS_FROZEN;
- return Py_INCREF_RET((PyObject *)self);;
+ return Py_INCREF_RET((PyObject *)self);
}
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 67905f8e340..817173c5bc6 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1858,7 +1858,7 @@ static PyObject *Matrix_zero(MatrixObject *self)
if (BaseMath_Prepare_ForWrite(self) == -1)
return NULL;
- fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
+ copy_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
@@ -2757,7 +2757,7 @@ PyDoc_STRVAR(matrix_doc,
" matrices from 2x2 up to 4x4.\n"
"\n"
" :param rows: Sequence of rows.\n"
-" When ommitted, a 4x4 identity matrix is constructed.\n"
+" When ommitted, a 4x4 identity matrix is constructed.\n"
" :type rows: 2d number sequence\n"
);
PyTypeObject matrix_Type = {
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index a33b55c35dc..3d7a505eb12 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -76,7 +76,7 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- fill_vn_fl(vec, size, 0.0f);
+ copy_vn_fl(vec, size, 0.0f);
break;
case 1:
if ((size = mathutils_array_parse_alloc(&vec, 2, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1) {
@@ -142,7 +142,7 @@ static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args)
return NULL;
}
- fill_vn_fl(vec, size, fill);
+ copy_vn_fl(vec, size, fill);
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
}
@@ -339,7 +339,7 @@ static PyObject *Vector_zero(VectorObject *self)
if (BaseMath_Prepare_ForWrite(self) == -1)
return NULL;
- fill_vn_fl(self->vec, self->size, 0.0f);
+ copy_vn_fl(self->vec, self->size, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
@@ -426,7 +426,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
/* If the vector has increased in length, set all new elements to 0.0f */
if (size > self->size) {
- fill_vn_fl(self->vec + self->size, size - self->size, 0.0f);
+ copy_vn_fl(self->vec + self->size, size - self->size, 0.0f);
}
self->size = size;
@@ -465,7 +465,7 @@ static PyObject *Vector_resized(VectorObject *self, PyObject *value)
return NULL;
}
- fill_vn_fl(vec, size, 0.0f);
+ copy_vn_fl(vec, size, 0.0f);
memcpy(vec, self->vec, self->size * sizeof(float));
return Vector_CreatePyObject_alloc(vec, size, NULL);
@@ -2236,7 +2236,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
return -1;
}
if (param == 0.0) {
- fill_vn_fl(self->vec, self->size, 0.0f);
+ copy_vn_fl(self->vec, self->size, 0.0f);
return 0;
}
@@ -3030,7 +3030,7 @@ PyObject *Vector_CreatePyObject(
memcpy(self->vec, vec, size * sizeof(float));
}
else { /* new empty */
- fill_vn_fl(self->vec, size, 0.0f);
+ copy_vn_fl(self->vec, size, 0.0f);
if (size == 4) { /* do the homogeneous thing */
self->vec[3] = 1.0f;
}
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index bb4080decef..ae5c058406f 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -850,7 +850,7 @@ PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
"\n"
" Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, \n"
" only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n"
-" Works only with convex quads without singular edges."
+" Works only with convex quads without singular edges.\n"
"\n"
" :arg pt: Point\n"
" :type pt: :class:`mathutils.Vector`\n"
diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m
index cbc76e26aa9..db2d4e72dc5 100644
--- a/source/blender/quicktime/apple/qtkit_export.m
+++ b/source/blender/quicktime/apple/qtkit_export.m
@@ -98,8 +98,6 @@ typedef struct QuicktimeExport {
} QuicktimeExport;
-static struct QuicktimeExport *qtexport;
-
#define AUDIOOUTPUTBUFFERSIZE 65536
#pragma mark rna helper functions
@@ -219,10 +217,21 @@ static NSString *stringWithCodecType(int codecType)
return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
}
-void makeqtstring(RenderData *rd, char *string)
+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);
@@ -234,10 +243,21 @@ void makeqtstring(RenderData *rd, char *string)
}
}
-void filepath_qt(char *string, RenderData *rd)
+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);
@@ -245,17 +265,32 @@ void filepath_qt(char *string, RenderData *rd)
if (rd->scemode & R_EXTENSION) {
if (!BLI_testextensie(string, ".mov")) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, ".mov");
}
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ 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
@@ -280,12 +315,13 @@ static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile)
}
/* AudioConverter input stream callback */
-static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
+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;
@@ -312,15 +348,24 @@ static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
#pragma mark export functions
-int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports)
+int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int 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 (qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
[QTMovie enterQTKitOnThread];
@@ -330,7 +375,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
success = 0;
}
else {
- makeqtstring(rd, name);
+ makeqtstring(rd, name, preview);
qtexport->filename = [[NSString alloc] initWithCString:name
encoding:[NSString defaultCStringEncoding]];
qtexport->movie = nil;
@@ -591,13 +636,13 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
specs.format = U.audioformat;
specs.rate = U.audiorate;
qtexport->audioInputDevice = AUD_openReadDevice(specs);
- AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, rd->sfra * rd->frs_sec_base / rd->frs_sec);
+ 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 = (rd->efra - rd->sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
+ qtexport->audioLastFrame = (efra - sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
}
}
}
@@ -607,7 +652,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
return success;
}
-int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
+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;
@@ -615,6 +660,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
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
@@ -654,7 +700,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
UInt32 audioPacketsConverted;
// Upper limit on total exported audio frames for this particular video frame
- const UInt64 exportedAudioFrameLimit = (frame - rd->sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
+ const UInt64 exportedAudioFrameLimit = (frame - start_frame) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
/* Append audio */
while (qtexport->audioTotalExportedFrames < exportedAudioFrameLimit) {
@@ -672,7 +718,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
audioPacketsConverted = 1;
err = AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback,
- NULL, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
+ qtexport, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
if (audioPacketsConverted) {
AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize,
qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer);
@@ -705,9 +751,11 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
}
-void end_qt(void)
+void end_qt(void *context_v)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ QuicktimeExport *qtexport = context_v;
+
if (qtexport->movie) {
if (qtexport->audioFile)
@@ -798,11 +846,6 @@ void end_qt(void)
}
[QTMovie exitQTKitOnThread];
-
- if (qtexport) {
- MEM_freeN(qtexport);
- qtexport = NULL;
- }
[pool drain];
}
diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h
index a499cd462b7..8a10a4a05d6 100644
--- a/source/blender/quicktime/quicktime_export.h
+++ b/source/blender/quicktime/quicktime_export.h
@@ -54,12 +54,13 @@ struct ImageFormatData;
struct RenderData;
struct ReportList;
struct Scene;
-struct wmOperatorType;
-int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports); //for movie handle (BKE writeavi.c now)
-int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
-void end_qt(void);
-void filepath_qt(char *string, struct RenderData *rd);
+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
@@ -76,7 +77,7 @@ 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); //for playanim.c
+void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 36b9f8ae362..4b54ddf7225 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../blenkernel
../blenlib
../imbuf
+ ../depsgraph
../makesdna
../makesrna
../physics
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index 0cbf188525b..4a9f32bc1ac 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -38,6 +38,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../imbuf',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../physics',
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index 481da452529..0750ea1aa28 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -32,6 +32,7 @@
#ifndef __RE_BAKE_H__
#define __RE_BAKE_H__
+struct ImBuf;
struct Render;
struct Mesh;
@@ -49,29 +50,28 @@ typedef struct BakeImages {
} BakeImages;
typedef struct BakePixel {
- int primitive_id;
+ int primitive_id, object_id;
float uv[2];
float du_dx, du_dy;
float dv_dx, dv_dy;
} BakePixel;
typedef struct BakeHighPolyData {
- struct BakePixel *pixel_array;
struct Object *ob;
struct ModifierData *tri_mod;
struct Mesh *me;
char restrict_flag;
+ bool is_flip_object;
float obmat[4][4];
float imat[4][4];
- float rotmat[4][4];
} BakeHighPolyData;
/* external_engine.c */
bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
- struct Render *re, struct Object *object, const BakePixel pixel_array[],
+ struct Render *re, struct Object *object, const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
/* bake.c */
@@ -81,7 +81,7 @@ bool RE_bake_internal(
const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
bool RE_bake_pixels_populate_from_objects(
- struct Mesh *me_low, BakePixel pixel_array_from[],
+ struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[],
BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage,
const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage);
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 5edf970c129..4e48060c54f 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -61,6 +61,7 @@ struct BakePixel;
#define RE_USE_EXCLUDE_LAYERS 32
#define RE_USE_SAVE_BUFFERS 64
#define RE_USE_TEXTURE_PREVIEW 128
+#define RE_USE_SHADING_NODES_CUSTOM 256
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -88,7 +89,7 @@ typedef struct RenderEngineType {
void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
void (*render)(struct RenderEngine *engine, struct Scene *scene);
- void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
+ void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
@@ -135,10 +136,14 @@ void RE_engine_free(RenderEngine *engine);
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename);
-struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername);
+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_active_view_set(RenderEngine *engine, const char *viewname);
+float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera);
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, float *r_modelmat);
+
int RE_engine_test_break(RenderEngine *engine);
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
void RE_engine_update_progress(RenderEngine *engine, float progress);
@@ -159,7 +164,7 @@ void RE_engines_exit(void);
RenderEngineType *RE_engines_find(const char *idname);
-void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r);
+rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);
struct RenderData *RE_engine_get_render_data(struct Render *re);
void RE_bake_engine_set_engine_parameters(struct Render *re, struct Main *bmain, struct Scene *scene);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index d1b6673c792..4b6004cea3d 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -35,8 +35,10 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+struct bMovieHandle;
struct bNodeTree;
struct Image;
+struct ImageFormatData;
struct Main;
struct NodeBlurData;
struct Object;
@@ -46,6 +48,8 @@ struct ReportList;
struct Scene;
struct SceneRenderLayer;
struct EnvMap;
+struct RenderResult;
+struct StampData;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is what is exposed of render to outside world */
@@ -65,6 +69,19 @@ typedef struct Render Render;
* and how it's converted
*/
+typedef struct RenderView {
+ struct RenderView *next, *prev;
+ char name[64]; /* EXR_VIEW_MAXNAME */
+
+ /* if this exists, result of composited layers */
+ float *rectf;
+ /* if this exists, result of composited layers */
+ float *rectz;
+ /* optional, 32 bits version of picture, used for sequencer, ogl render and image curves */
+ int *rect32;
+
+} RenderView;
+
typedef struct RenderPass {
struct RenderPass *next, *prev;
int passtype, channels;
@@ -72,16 +89,23 @@ typedef struct RenderPass {
char chan_id[8]; /* amount defined in openexr_multi.h */
float *rect;
int rectx, recty;
+
+ char internal_name[64]; /* EXR_PASS_MAXNAME */
+ char view[64]; /* EXR_VIEW_MAXNAME */
+ int view_id; /* quick lookup */
+
int debug_type;
} 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 */
-/* after render, the Combined pass is in rectf, for renderlayers read from files it is a real pass */
+/* after render, the Combined pass is in combined, for renderlayers read from files it is a real pass */
typedef struct RenderLayer {
struct RenderLayer *next, *prev;
@@ -92,8 +116,10 @@ typedef struct RenderLayer {
struct Material *mat_override;
struct Group *light_override;
-
- float *rectf; /* 4 float, standard rgba buffer (read not above!) */
+
+ /* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment.
+ * If they are really required they should be in RenderView instead */
+
float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */
float *scolrect; /* 4 float, optional strand buffer, needs storage for display updates */
int *display_buffer; /* 4 char, optional color managed display buffer which is used when
@@ -114,6 +140,9 @@ typedef struct RenderResult {
int rectx, recty;
short crop, sample_nr;
+ /* the following rect32, rectf and rectz buffers are for temporary storage only, for RenderResult structs
+ * created in #RE_AcquireResultImage - which do not have RenderView */
+
/* optional, 32 bits version of picture, used for ogl render and image curves */
int *rect32;
/* if this exists, a copy of one of layers, or result of composited layers */
@@ -129,6 +158,9 @@ typedef struct RenderResult {
/* the main buffers */
ListBase layers;
+ /* multiView maps to a StringVector in OpenEXR */
+ ListBase views;
+
/* allowing live updates: */
volatile rcti renrect;
volatile RenderLayer *renlay;
@@ -145,6 +177,8 @@ typedef struct RenderResult {
/* render info text */
char *text;
char *error;
+
+ struct StampData *stamp_data;
} RenderResult;
@@ -183,16 +217,18 @@ void RE_FreeRenderResult(struct RenderResult *rr);
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
-void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr);
+void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr);
+void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
+void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
-void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect);
+void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
-float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype);
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
@@ -203,6 +239,7 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
/* set up the viewplane/perspective matrix, three choices */
struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
+void RE_SetOverrideCamera(struct Render *re, struct Object *camera);
void RE_SetCamera(struct Render *re, struct Object *camera);
void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend);
void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend);
@@ -232,6 +269,11 @@ void RE_init_threadcount(Render *re);
/* the main processor, assumes all was set OK! */
void RE_TileProcessor(struct Render *re);
+bool RE_WriteRenderViewsImage(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name);
+bool RE_WriteRenderViewsMovie(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, struct RenderData *rd,
+ struct bMovieHandle *mh, const size_t width, const size_t height, void **movie_ctx_arr,
+ const size_t totvideos, bool preview);
+
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene,
struct SceneRenderLayer *srl, struct Object *camera_override,
@@ -243,6 +285,9 @@ void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Sce
void RE_RenderFreestyleExternal(struct Render *re);
#endif
+void RE_SetActiveRenderView(struct Render *re, const char *viewname);
+const char *RE_GetActiveRenderView(struct Render *re);
+
/* error reporting */
void RE_SetReports(struct Render *re, struct ReportList *reports);
@@ -250,7 +295,7 @@ void RE_SetReports(struct Render *re, struct ReportList *reports);
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
-bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, int compress);
+bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view);
struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
extern const float default_envmap_layout[];
@@ -276,6 +321,10 @@ void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize,
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_type(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+
/* shaded view or baking options */
#define RE_BAKE_LIGHT 0 /* not listed in rna_scene.c -> can't be enabled! */
#define RE_BAKE_ALL 1
@@ -297,6 +346,7 @@ void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *sce
void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
+void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
struct Scene *RE_GetScene(struct Render *re);
bool RE_force_single_renderlayer(struct Scene *scene);
@@ -304,5 +354,12 @@ bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override
bool RE_allow_render_generic_object(struct Object *ob);
+/******* defined in render_result.c *********/
+
+bool RE_HasFakeLayer(RenderResult *res);
+bool RE_RenderResult_is_stereo(RenderResult *res);
+struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id);
+struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname);
+
#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 d76d16a641e..6adbb6d0e62 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -39,10 +39,8 @@
/* called by meshtools */
struct DerivedMesh;
struct ImagePool;
-struct LinkNode;
struct MTex;
struct Scene;
-struct View3D;
/* 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 int thread, struct ImagePool *pool, const bool skip_load_image);
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
index 1f11cdc6729..87e2d2519d5 100644
--- a/source/blender/render/intern/include/initrender.h
+++ b/source/blender/render/intern/include/initrender.h
@@ -33,7 +33,6 @@
#ifndef __INITRENDER_H__
#define __INITRENDER_H__
-struct Object;
/* Functions */
diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/render/intern/include/occlusion.h
index 2f3ac2a7bff..4a70d691436 100644
--- a/source/blender/render/intern/include/occlusion.h
+++ b/source/blender/render/intern/include/occlusion.h
@@ -35,11 +35,8 @@
struct Render;
struct ShadeInput;
-struct ShadeResult;
struct RenderPart;
struct ShadeSample;
-struct DerivedMesh;
-struct ObjectRen;
void make_occ_tree(struct Render *re);
void free_occ(struct Render *re);
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
index faf8c5f54f5..8f23455564f 100644
--- a/source/blender/render/intern/include/pixelshading.h
+++ b/source/blender/render/intern/include/pixelshading.h
@@ -32,7 +32,6 @@
#ifndef __PIXELSHADING_H__
#define __PIXELSHADING_H__
-struct ImagePool;
/**
* Render the pixel at (x,y) for object ap. Apply the jitter mask.
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
index e0c293e2473..1d1e808e8d3 100644
--- a/source/blender/render/intern/include/pointdensity.h
+++ b/source/blender/render/intern/include/pointdensity.h
@@ -37,10 +37,12 @@
* Make point density kd-trees for all point density textures in the scene
*/
+struct PointDensity;
struct Render;
struct TexResult;
-void cache_pointdensity(struct Render *re, struct Tex *tex);
+void free_pointdensity(struct PointDensity *pd);
+void cache_pointdensity(struct Render *re, struct PointDensity *pd);
void make_pointdensities(struct Render *re);
void free_pointdensities(struct Render *re);
int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 90ff69dbfbe..90ad0fa30d7 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -38,6 +38,7 @@
#define RR_USE_EXR 1
#define RR_ALL_LAYERS NULL
+#define RR_ALL_VIEWS NULL
struct ImBuf;
struct ListBase;
@@ -53,12 +54,15 @@ struct ColorManagedViewSettings;
/* New */
struct RenderResult *render_result_new(struct Render *re,
- struct rcti *partrct, int crop, int savebuffers, const char *layername);
+ struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname);
struct RenderResult *render_result_new_full_sample(struct Render *re,
- struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers);
+ struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname);
struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
+void render_result_view_new(struct RenderResult *rr, const char *viewname);
+void render_result_views_new(struct RenderResult *rr, struct RenderData *rd);
+
/* Merge */
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
@@ -75,10 +79,11 @@ void render_result_single_layer_end(struct Render *re);
/* EXR Tile File Render */
+void render_result_save_empty_result_tiles(struct Render *re);
void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
-void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart);
+void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);
int render_result_exr_file_read_sample(struct Render *re, int sample);
@@ -91,15 +96,19 @@ bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
-struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd);
+struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd, const int view_id);
void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
- struct ImBuf *ibuf);
+ struct ImBuf *ibuf, const int view_id);
-void render_result_rect_fill_zero(struct RenderResult *rr);
+void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id);
void render_result_rect_get_pixels(struct RenderResult *rr,
unsigned int *rect, int rectx, int recty,
const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings);
+ const struct ColorManagedDisplaySettings *display_settings,
+ const int view_id);
+
+void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src);
+void render_result_views_shallowdelete(struct RenderResult *rr);
#endif /* __RENDER_RESULT_H__ */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 8d92fb9eec9..e12a1575992 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -58,7 +58,6 @@ struct MemArena;
struct VertTableNode;
struct VlakTableNode;
struct GHash;
-struct RenderBuckets;
struct ObjectInstanceRen;
struct RayObject;
struct RayFace;
@@ -123,8 +122,7 @@ enum {
};
/* controls state of render, everything that's read-only during render stage */
-struct Render
-{
+struct Render {
struct Render *next, *prev;
char name[RE_MAXNAME];
int slot;
@@ -194,6 +192,7 @@ struct Render
struct Object *camera_override;
unsigned int lay, layer_override;
+ ThreadRWMutex partsmutex;
ListBase parts;
/* render engine */
@@ -275,6 +274,9 @@ struct Render
struct ImagePool *pool;
struct EvaluationContext *eval_ctx;
+
+ void **movie_ctx_arr;
+ char viewname[MAX_NAME];
};
/* ------------------------------------------------------------------------- */
@@ -388,7 +390,6 @@ struct halosort {
/* ------------------------------------------------------------------------- */
struct Material;
-struct MTFace;
struct ImagePool;
typedef struct RadFace {
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 88b639c4ba9..308903c6c6d 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -34,14 +34,11 @@
#include "render_types.h"
-struct HaloRen;
struct ShadeInput;
struct ShadeResult;
struct World;
struct RenderPart;
struct RenderLayer;
-struct ObjectRen;
-struct ListBase;
struct RayObject;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
index 7c168baada7..ece6902b6b2 100644
--- a/source/blender/render/intern/include/shadbuf.h
+++ b/source/blender/render/intern/include/shadbuf.h
@@ -34,7 +34,6 @@
#include "render_types.h"
-struct ObjectRen;
/**
* Calculates shadowbuffers for a vector of shadow-giving lamps
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 4f6e005d742..11dcc9d9e80 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -33,7 +33,6 @@ struct RenderLayer;
struct PixStr;
struct LampRen;
struct VlakRen;
-struct StrandSegment;
struct StrandPoint;
struct ObjectInstanceRen;
struct Isect;
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
index 91a8b91e638..0952c6bff65 100644
--- a/source/blender/render/intern/include/sss.h
+++ b/source/blender/render/intern/include/sss.h
@@ -55,7 +55,6 @@ void scatter_tree_free(ScatterTree *tree);
struct Render;
struct Material;
-struct VlakRen;
void make_sss_tree(struct Render *re);
void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint);
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
index fdcce687f54..5687ef3c837 100644
--- a/source/blender/render/intern/include/strand.h
+++ b/source/blender/render/intern/include/strand.h
@@ -34,9 +34,6 @@ struct StrandBuffer;
struct ShadeSample;
struct StrandPart;
struct Render;
-struct RenderPart;
-struct RenderBuckets;
-struct RenderPrimitiveIterator;
struct ZSpan;
struct ObjectInstanceRen;
struct StrandSurface;
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index ebc83984306..ed161e186b8 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -56,6 +56,11 @@
_hsv[1] *= tex->saturation; \
hsv_to_rgb(_hsv[0], _hsv[1], _hsv[2], \
&texres->tr, &texres->tg, &texres->tb); \
+ if ((tex->saturation > 1.0f) && !(tex->flag & TEX_NO_CLAMP)) { \
+ if (texres->tr < 0.0f) texres->tr= 0.0f; \
+ if (texres->tg < 0.0f) texres->tg= 0.0f; \
+ if (texres->tb < 0.0f) texres->tb= 0.0f; \
+ } \
} \
struct HaloRen;
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index ec30c3241ab..cf804d75d70 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -36,7 +36,6 @@
struct RenderPart;
struct RenderLayer;
struct LampRen;
-struct VlakRen;
struct ListBase;
struct ZSpan;
struct APixstrand;
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index 01e592cba0c..d080ddcc375 100644
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -197,7 +197,7 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
//There must be a faster way than rotating all the 8 vertexs of the BB
for (i = 0; i < 8; i++) {
- for (j = 0; j < 3; j++) t[j] = i & (1 << j) ? M[j] : m[j];
+ for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
mul_m4_v3(obj->target2global, t);
DO_MINMAX(t, min, max);
}
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index 4aa2f4e919e..0210bec5ab4 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -75,6 +76,8 @@ extern struct Render R;
typedef struct BakeShade {
+ int thread;
+
ShadeSample ssamp;
ObjectInstanceRen *obi;
VlakRen *vlr;
@@ -737,6 +740,9 @@ static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
MLoopCol *basevcol;
MLoop *mloop;
+ /* per vertex fixed seed */
+ BLI_thread_srandom(bs->thread, vert->index);
+
origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
if (!origindex || *origindex == ORIGINDEX_NONE)
return;
@@ -811,6 +817,9 @@ static void shade_tface(BakeShade *bs)
Image *ima = tface->tpage;
float vec[4][2];
int a, i1, i2, i3;
+
+ /* per face fixed seed */
+ BLI_thread_srandom(bs->thread, vlr->index);
/* check valid zspan */
if (ima != bs->ima) {
@@ -984,8 +993,12 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
int a, vdone = false, result = BAKE_RESULT_OK;
bool use_mask = false;
bool use_displacement_buffer = false;
- bool do_manage = BKE_scene_check_color_management_enabled(re->scene);
-
+ bool do_manage = false;
+
+ if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
+ do_manage = BKE_scene_check_color_management_enabled(re->scene);
+ }
+
re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
/* initialize render global */
@@ -1033,6 +1046,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
/* get the threads running */
for (a = 0; a < re->r.threads; a++) {
+ handles[a].thread = a;
+
/* set defaults in handles */
handles[a].ssamp.shi[0].lay = re->lay;
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index ecfb86c8d17..bc5db5b9862 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -30,10 +30,11 @@
*
* The Bake API is fully implemented with Python rna functions. The operator expects/call a function:
*
- * ``def bake(scene, object, pass_type, pixel_array, num_pixels, depth, result)``
+ * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)``
* - scene: current scene (Python object)
* - object: object to render (Python object)
* - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...)
+ * - object_id: index of object to bake (to use with the pixel_array)
* - pixel_array: list of primitive ids and barycentric coordinates to bake(Python object, see bake_pixel)
* - num_pixels: size of pixel_array, number of pixels to bake (int)
* - depth: depth of pixels to return (int, assuming always 4 now)
@@ -47,7 +48,7 @@
*
* \code{.c}
* struct BakePixel {
- * int primitive_id;
+ * int primitive_id, object_id;
* float uv[2];
* float du_dx, du_dy;
* float dv_dx, dv_dy;
@@ -55,7 +56,7 @@
* \endcode
*
* In python you have access to:
- * - ``primitive_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
+ * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
* - ``next()`` is a function that returns the next #BakePixel in the array.
*
* \note Pixels that should not be baked have ``primitive_id == -1``
@@ -126,12 +127,16 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v)
pixel = &bd->pixel_array[i];
pixel->primitive_id = bd->primitive_id;
+ /* At this point object_id is always 0, since this function runs for the
+ * lowpoly mesh only. The object_id lookup indices are set afterwards. */
+
copy_v2_fl2(pixel->uv, u, v);
pixel->du_dx = bd->du_dx;
pixel->du_dy = bd->du_dy;
pixel->dv_dx = bd->dv_dx;
pixel->dv_dy = bd->dv_dy;
+ pixel->object_id = 0;
}
void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask)
@@ -271,7 +276,7 @@ static void calc_barycentric_from_point(
* This function populates pixel_array and returns TRUE if things are correct
*/
static bool cast_ray_highpoly(
- BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakeHighPolyData *highpoly,
+ BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
{
@@ -295,7 +300,7 @@ static bool cast_ray_highpoly(
mul_v3_m4v3(co_high, highpoly[i].imat, co);
/* rotates */
- mul_v3_m4v3(dir_high, highpoly[i].rotmat, dir);
+ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
normalize_v3(dir_high);
/* cast ray */
@@ -322,22 +327,22 @@ static bool cast_ray_highpoly(
}
}
- for (i = 0; i < tot_highpoly; i++) {
- if (hit_mesh == i) {
- calc_barycentric_from_point(triangles[i], hits[i].index, hits[i].co, &primitive_id, uv);
- highpoly[i].pixel_array[pixel_id].primitive_id = primitive_id;
- copy_v2_v2(highpoly[i].pixel_array[pixel_id].uv, uv);
-
- /* the differentials are relative to the UV/image space, so the highpoly differentials
- * are the same as the low poly differentials */
- highpoly[i].pixel_array[pixel_id].du_dx = du_dx;
- highpoly[i].pixel_array[pixel_id].du_dy = du_dy;
- highpoly[i].pixel_array[pixel_id].dv_dx = dv_dx;
- highpoly[i].pixel_array[pixel_id].dv_dy = dv_dy;
- }
- else {
- highpoly[i].pixel_array[pixel_id].primitive_id = -1;
- }
+ if (hit_mesh != -1) {
+ calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
+ pixel_array[pixel_id].primitive_id = primitive_id;
+ pixel_array[pixel_id].object_id = hit_mesh;
+ copy_v2_v2(pixel_array[pixel_id].uv, uv);
+
+ /* the differentials are relative to the UV/image space, so the highpoly differentials
+ * are the same as the low poly differentials */
+ pixel_array[pixel_id].du_dx = du_dx;
+ pixel_array[pixel_id].du_dy = du_dy;
+ pixel_array[pixel_id].dv_dx = dv_dx;
+ pixel_array[pixel_id].dv_dy = dv_dy;
+ }
+ else {
+ pixel_array[pixel_id].primitive_id = -1;
+ pixel_array[pixel_id].object_id = -1;
}
MEM_freeN(hits);
@@ -437,7 +442,7 @@ static void mesh_calc_tri_tessface(
}
bool RE_bake_pixels_populate_from_objects(
- struct Mesh *me_low, BakePixel pixel_array_from[],
+ struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[],
BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage,
const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage)
{
@@ -508,10 +513,7 @@ bool RE_bake_pixels_populate_from_objects(
primitive_id = pixel_array_from[i].primitive_id;
if (primitive_id == -1) {
- int j;
- for (j = 0; j < tot_highpoly; j++) {
- highpoly[j].pixel_array[i].primitive_id = -1;
- }
+ pixel_array_to[i].primitive_id = -1;
continue;
}
@@ -530,7 +532,7 @@ bool RE_bake_pixels_populate_from_objects(
}
/* cast ray */
- if (!cast_ray_highpoly(treeData, tris_high, highpoly, co, dir, i, tot_highpoly,
+ if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly,
pixel_array_from[i].du_dx, pixel_array_from[i].du_dy,
pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) {
/* if it fails mask out the original pixel array */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 2ebcb76e3d1..1da1a81fe95 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -577,6 +577,17 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor
VlakRen *vlr;
int a, totvert;
+ float rot[3][3];
+
+ /* Note: For normals, we only want rotation, not scaling component.
+ * Negative scales (aka mirroring) give wrong results, see T44102. */
+ if (lnors) {
+ float mat3[3][3], size[3];
+
+ copy_m3_m4(mat3, mat);
+ mat3_to_rot_size(rot, size, mat3);
+ }
+
if (obr->totvert == 0)
return;
@@ -611,9 +622,8 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor
ver = RE_findOrAddVert(obr, a);
mul_m4_v3(mat, ver->co);
if (lnors) {
- mul_mat3_m4_v3(mat, ver->n);
+ mul_m3_v3(rot, ver->n);
negate_v3(ver->n);
- normalize_v3(ver->n);
}
}
for (a = 0; a < obr->totvlak; a++) {
@@ -1199,8 +1209,7 @@ static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re
sd->time = 0.0f;
sd->size = hasize;
- copy_v3_v3(vel, state->vel);
- mul_mat3_m4_v3(re->viewmat, vel);
+ mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
normalize_v3(vel);
if (part->draw & PART_DRAW_VEL_LENGTH)
@@ -3270,12 +3279,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
ma= give_render_material(re, ob, a1+1);
-
+
/* test for 100% transparent */
ok = 1;
if ((ma->alpha == 0.0f) &&
(ma->spectra == 0.0f) &&
- (ma->filter == 0.0f) &&
+ /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
+ /* (ma->filter == 0.0f) && */
(ma->mode & MA_TRANSP) &&
(ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
{
@@ -3803,7 +3813,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
}
/* set flag for spothalo en initvars */
- if (la->type==LA_SPOT && (la->mode & LA_HALO) && (la->buftype != LA_SHADBUF_DEEP)) {
+ if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
+ (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
+ {
if (la->haint>0.0f) {
re->flag |= R_LAMPHALO;
@@ -3822,7 +3834,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
lar->sh_invcampos[2]*= lar->sh_zfac;
/* halfway shadow buffer doesn't work for volumetric effects */
- if (lar->buftype == LA_SHADBUF_HALFWAY)
+ if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
lar->buftype = LA_SHADBUF_REGULAR;
}
@@ -4992,7 +5004,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
* system need to have render settings set for dupli particles */
dupli_render_particle_set(re, ob, timeoffset, 0, 1);
duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
- duplilist_apply_data = duplilist_apply(ob, duplilist);
+ duplilist_apply_data = duplilist_apply(ob, NULL, duplilist);
dupli_render_particle_set(re, ob, timeoffset, 0, 0);
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
@@ -5159,8 +5171,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
* above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
* following calls don't depend on 'RE_SetCamera' */
RE_SetCamera(re, camera);
-
- normalize_m4_m4(mat, camera->obmat);
+ RE_GetCameraModelMatrix(re, camera, mat);
invert_m4(mat);
RE_SetView(re, mat);
@@ -5330,7 +5341,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
/* if no camera, viewmat should have been set! */
if (camera) {
- normalize_m4_m4(mat, camera->obmat);
+ RE_GetCameraModelMatrix(re, camera, mat);
+ normalize_m4(mat);
invert_m4(mat);
RE_SetView(re, mat);
}
@@ -5841,9 +5853,11 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
/* renderdata setup and exceptions */
BLI_freelistN(&re->r.layers);
+ BLI_freelistN(&re->r.views);
re->r = scene->r;
BLI_duplicatelist(&re->r.layers, &scene->r.layers);
-
+ BLI_duplicatelist(&re->r.views, &scene->r.views);
+
RE_init_threadcount(re);
re->flag |= R_BAKING;
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index f0268836104..23d021db848 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -70,7 +70,7 @@ static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
BLI_lock_thread(LOCK_IMAGE);
if (env->cube[1] == NULL) {
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
dx = ibuf->y;
dx /= 2;
@@ -141,6 +141,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
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);
envre->r.filtertype = 0;
envre->r.tilex = envre->r.xsch / 2;
envre->r.tiley = envre->r.ysch / 2;
@@ -495,9 +496,11 @@ static void render_envmap(Render *re, EnvMap *env)
RenderLayer *rl = envre->result->layers.first;
int y;
float *alpha;
-
+ float *rect;
+
+ rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
- memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
+ memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
/* envmap renders without alpha */
alpha = ibuf->rect_float + 3;
@@ -511,7 +514,7 @@ static void render_envmap(Render *re, EnvMap *env)
}
- if (re->test_break(re->tbh)) BKE_free_envmapdata(env);
+ if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env);
else {
if (envre->r.mode & R_OSA) env->ok = ENV_OSA;
else env->ok = ENV_NORMAL;
@@ -572,13 +575,13 @@ void make_envmaps(Render *re)
if (env->ok) {
/* free when OSA, and old one isn't OSA */
if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
/* free when size larger */
else if (env->lastsize < re->r.size)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
/* free when env is in recalcmode */
else if (env->recalc)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
}
if (env->ok == 0 && depth == 0) env->recalc = 1;
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 4e63a9918e1..63d1b609621 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -42,6 +42,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -181,7 +182,7 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result)
return NULL;
}
-RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
+RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
Render *re = engine->re;
RenderResult *result;
@@ -204,7 +205,7 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
disprect.ymin = y;
disprect.ymax = y + h;
- result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername);
+ result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
/* todo: make this thread safe */
@@ -269,7 +270,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
if (!cancel || merge_results) {
if (re->result->do_exr_tile) {
if (!cancel) {
- render_result_exr_file_merge(re->result, result);
+ render_result_exr_file_merge(re->result, result, re->viewname);
}
}
else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW)))
@@ -368,28 +369,56 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
}
}
-void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
+void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
{
+ Render *re = engine->re;
+ RE_SetActiveRenderView(re, viewname);
+}
+
+float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera)
+{
+ Render *re = engine->re;
+ return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
+}
+
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat)
+{
+ Render *re = engine->re;
+ BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat);
+}
+
+rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
+{
+ static rcti tiles_static[BLENDER_MAX_THREADS];
+ const int allocation_step = BLENDER_MAX_THREADS;
RenderPart *pa;
int total_tiles = 0;
- rcti *tiles = NULL;
- int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS;
+ rcti *tiles = tiles_static;
+ int allocation_size = BLENDER_MAX_THREADS;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_READ);
+
+ *r_needs_free = false;
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
- *total_tiles_r = 0;
- *tiles_r = NULL;
- return;
+ *r_total_tiles = 0;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ return NULL;
}
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status == PART_STATUS_IN_PROGRESS) {
if (total_tiles >= allocation_size) {
- if (tiles == NULL)
+ /* Just in case we're using crazy network rendering with more
+ * slaves as BLENDER_MAX_THREADS.
+ */
+ if (tiles == tiles_static)
tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles");
else
tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti));
allocation_size += allocation_step;
+ *r_needs_free = true;
}
tiles[total_tiles] = pa->disprect;
@@ -404,9 +433,9 @@ void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
total_tiles++;
}
}
-
- *total_tiles_r = total_tiles;
- *tiles_r = tiles;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ *r_total_tiles = total_tiles;
+ return tiles;
}
RenderData *RE_engine_get_render_data(Render *re)
@@ -425,6 +454,7 @@ void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
* but it potentially leaves unfreed memory blocks
* not sure how to fix this yet -- dfelinto */
BLI_listbase_clear(&re->r.layers);
+ BLI_listbase_clear(&re->r.views);
}
bool RE_bake_has_engine(Render *re)
@@ -434,7 +464,8 @@ bool RE_bake_has_engine(Render *re)
}
bool RE_bake_engine(
- Render *re, Object *object, const BakePixel pixel_array[],
+ Render *re, Object *object,
+ const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth,
const ScenePassType pass_type, float result[])
{
@@ -472,12 +503,14 @@ bool RE_bake_engine(
type->update(engine, re->main, re->scene);
if (type->bake)
- type->bake(engine, re->scene, object, pass_type, pixel_array, num_pixels, depth, result);
+ type->bake(engine, re->scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result);
engine->tile_x = 0;
engine->tile_y = 0;
engine->flag &= ~RE_ENGINE_RENDERING;
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
@@ -485,6 +518,7 @@ bool RE_bake_engine(
}
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
@@ -599,7 +633,7 @@ int RE_engine_render(Render *re, int do_all)
if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE))
savebuffers = RR_USE_EXR;
- re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
}
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -663,6 +697,8 @@ int RE_engine_render(Render *re, int do_all)
render_result_free_list(&engine->fullresult, engine->fullresult.first);
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
@@ -671,6 +707,7 @@ int RE_engine_render(Render *re, int do_all)
if (re->result->do_exr_tile) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_save_empty_result_tiles(re);
render_result_exr_file_end(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
@@ -682,6 +719,7 @@ int RE_engine_render(Render *re, int do_all)
}
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index a0fcc7cdcd2..970a3937657 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -426,10 +426,10 @@ void make_sample_tables(Render *re)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
struct Object *RE_GetCamera(Render *re)
{
- return re->camera_override ? re->camera_override : re->scene->camera;
+ Object *camera = re->camera_override ? re->camera_override : re->scene->camera;
+ return BKE_camera_multiview_render(re->scene, camera, re->viewname);
}
static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_ob)
@@ -470,6 +470,16 @@ void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clips
re_camera_params_get(re, &params, cam_ob);
}
+void RE_SetOverrideCamera(Render *re, Object *camera)
+{
+ re->camera_override = camera;
+}
+
+static void re_camera_params_stereo3d(Render *re, CameraParams *params, Object *cam_ob)
+{
+ BKE_camera_multiview_params(&re->r, params, cam_ob, re->viewname);
+}
+
/* call this after InitState() */
/* per render, there's one persistent viewplane. Parts will set their own viewplanes */
void RE_SetCamera(Render *re, Object *cam_ob)
@@ -479,6 +489,7 @@ void RE_SetCamera(Render *re, Object *cam_ob)
/* setup parameters */
BKE_camera_params_init(&params);
BKE_camera_params_from_object(&params, cam_ob);
+ re_camera_params_stereo3d(re, &params, cam_ob);
params.use_fields = (re->r.mode & R_FIELDS);
params.field_second = (re->flag & R_SEC_FIELD);
@@ -505,6 +516,11 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo
copy_m4_m4(mat, re->winmat);
}
+void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4])
+{
+ BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat);
+}
+
/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 6ba85ea5329..de57d4e7ba6 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -127,9 +127,13 @@ typedef struct {
static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int face_num, const int vert_index)
{
- unsigned int indices[] = {data->mface[face_num].v1, data->mface[face_num].v2,
- data->mface[face_num].v3, data->mface[face_num].v4};
- const int smoothnormal = (data->mface[face_num].flag & ME_SMOOTH);
+ const unsigned int indices[] = {
+ data->mface[face_num].v1,
+ data->mface[face_num].v2,
+ data->mface[face_num].v3,
+ data->mface[face_num].v4,
+ };
+ const bool smoothnormal = (data->mface[face_num].flag & ME_SMOOTH) != 0;
if (!smoothnormal) { /* flat */
if (data->precomputed_normals) {
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 21ca7924fa0..1fa2673f12c 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -70,6 +70,7 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
+#include "BKE_object.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -83,6 +84,8 @@
# include "FRS_freestyle.h"
#endif
+#include "DEG_depsgraph.h"
+
/* internal */
#include "render_result.h"
#include "render_types.h"
@@ -131,7 +134,7 @@ Render R;
/* ********* alloc and free ******** */
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override);
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override);
static volatile int g_break = 0;
static int thread_break(void *UNUSED(arg))
@@ -151,6 +154,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
{
uintptr_t mem_in_use, mmap_in_use, peak_memory;
float megs_used_memory, mmap_used_memory, megs_peak_memory;
+ char info_time_str[32];
mem_in_use = MEM_get_memory_in_use();
mmap_in_use = MEM_get_mapped_memory_in_use();
@@ -168,8 +172,11 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
if (rs->curblur)
fprintf(stdout, IFACE_("Blur %d "), rs->curblur);
+ BLI_timestr(PIL_check_seconds_timer() - rs->starttime, info_time_str, sizeof(info_time_str));
+ fprintf(stdout, IFACE_("| Time:%s | "), info_time_str);
+
if (rs->infostr) {
- fprintf(stdout, "| %s", rs->infostr);
+ fprintf(stdout, "%s", rs->infostr);
}
else {
if (rs->tothalo)
@@ -179,6 +186,9 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
fprintf(stdout, IFACE_("Sce: %s Ve:%d Fa:%d La:%d"), rs->scene_name, rs->totvert, rs->totface, rs->totlamp);
}
+ /* Flush stdout to be sure python callbacks are printing stuff after blender. */
+ fflush(stdout);
+
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS);
fputc('\n', stdout);
@@ -190,14 +200,10 @@ void RE_FreeRenderResult(RenderResult *res)
render_result_free(res);
}
-float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
+float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname)
{
- RenderPass *rpass;
-
- for (rpass = rl->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == passtype)
- return rpass->rect;
- return NULL;
+ RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname);
+ return rpass ? rpass->rect : NULL;
}
RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
@@ -307,8 +313,72 @@ Scene *RE_GetScene(Render *re)
return NULL;
}
+/**
+ * Same as #RE_AcquireResultImage but creating the necessary views to store the result
+ * fill provided result struct with a copy of thew views of what is done so far the
+ * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
+*/
+void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
+{
+ memset(rr, 0, sizeof(RenderResult));
+
+ if (re) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
+
+ if (re->result) {
+ RenderLayer *rl;
+ RenderView *rv, *rview;
+
+ rr->rectx = re->result->rectx;
+ rr->recty = re->result->recty;
+
+ /* creates a temporary duplication of views */
+ render_result_views_shallowcopy(rr, re->result);
+
+ rv = rr->views.first;
+
+ rr->have_combined = (rv->rectf != NULL);
+
+ /* active layer */
+ rl = render_get_active_layer(re, re->result);
+
+ 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);
+ }
+ }
+
+ if (rv->rectz == NULL) {
+ for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
+ rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name);
+ }
+ }
+ }
+
+ rr->layers = re->result->layers;
+ rr->xof = re->disprect.xmin;
+ rr->yof = re->disprect.ymin;
+ rr->stamp_data = re->result->stamp_data;
+ }
+ }
+}
+
+/* clear temporary renderresult struct */
+void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
+{
+ if (re) {
+ if (rr) {
+ render_result_views_shallowdelete(rr);
+ }
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+}
+
/* fill provided result struct with what's currently active or done */
-void RE_AcquireResultImage(Render *re, RenderResult *rr)
+/* this RenderResult struct is the only exception to the rule of a RenderResult */
+/* always having at least one RenderView */
+void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
{
memset(rr, 0, sizeof(RenderResult));
@@ -317,27 +387,33 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr)
if (re->result) {
RenderLayer *rl;
+ RenderView *rv;
rr->rectx = re->result->rectx;
rr->recty = re->result->recty;
- rr->rectf = re->result->rectf;
- rr->rectz = re->result->rectz;
- rr->rect32 = re->result->rect32;
-
+ /* actview view */
+ rv = RE_RenderViewGetById(re->result, view_id);
+
+ rr->rectf = rv->rectf;
+ rr->rectz = rv->rectz;
+ rr->rect32 = rv->rect32;
+
/* active layer */
rl = render_get_active_layer(re, re->result);
if (rl) {
- if (rr->rectf == NULL)
- rr->rectf = rl->rectf;
- if (rr->rectz == NULL)
- rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z);
+ if (rv->rectf == NULL)
+ rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name);
+
+ if (rv->rectz == NULL)
+ rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name);
}
- rr->have_combined = (re->result->rectf != NULL);
+ rr->have_combined = (rv->rectf != NULL);
rr->layers = re->result->layers;
-
+ rr->views = re->result->views;
+
rr->xof = re->disprect.xmin;
rr->yof = re->disprect.ymin;
}
@@ -354,17 +430,18 @@ void RE_ReleaseResultImage(Render *re)
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
-
- RE_AcquireResultImage(re, &rres);
- render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
- RE_ReleaseResultImage(re);
+ const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
+
+ RE_AcquireResultImageViews(re, &rres);
+ render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id);
+ RE_ReleaseResultImageViews(re, &rres);
}
/* caller is responsible for allocating rect in correct size! */
/* Only for acquired results, for lock */
-void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect)
+void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect, const int view_id)
{
- render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
+ render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id);
}
RenderStats *RE_GetStats(Render *re)
@@ -385,8 +462,8 @@ Render *RE_NewRender(const char *name)
BLI_addtail(&RenderGlobal.renderlist, re);
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
- re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx");
- re->eval_ctx->mode = DAG_EVAL_RENDER;
+ BLI_rw_mutex_init(&re->partsmutex);
+ re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
}
RE_InitRenderCB(re);
@@ -423,9 +500,11 @@ void RE_FreeRender(Render *re)
RE_engine_free(re->engine);
BLI_rw_mutex_end(&re->resultmutex);
+ BLI_rw_mutex_end(&re->partsmutex);
BLI_freelistN(&re->r.layers);
-
+ BLI_freelistN(&re->r.views);
+
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
@@ -572,8 +651,10 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
/* copy render data and render layers for thread safety */
BLI_freelistN(&re->r.layers);
+ BLI_freelistN(&re->r.views);
re->r = *rd;
BLI_duplicatelist(&re->r.layers, &rd->layers);
+ BLI_duplicatelist(&re->r.views, &rd->views);
if (source) {
/* reuse border flags from source renderer */
@@ -664,6 +745,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->result = MEM_callocN(sizeof(RenderResult), "new render result");
re->result->rectx = re->rectx;
re->result->recty = re->recty;
+ render_result_view_new(re->result, "new temporary view");
}
if (re->r.scemode & R_VIEWPORT_PREVIEW)
@@ -681,18 +763,23 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
RE_init_threadcount(re);
}
+/* This function is only called by view3d rendering, which doesn't support
+ * multiview at the moment. so handle only one view here */
static void render_result_rescale(Render *re)
{
RenderResult *result = re->result;
+ RenderView *rv;
int x, y;
float scale_x, scale_y;
float *src_rectf;
- src_rectf = result->rectf;
+ rv = RE_RenderViewGetById(result, 0);
+ src_rectf = rv->rectf;
+
if (src_rectf == NULL) {
RenderLayer *rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- src_rectf = rl->rectf;
+ src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
}
}
@@ -702,15 +789,16 @@ static void render_result_rescale(Render *re)
&re->disprect,
0,
RR_USE_MEM,
- RR_ALL_LAYERS);
+ RR_ALL_LAYERS,
+ "");
if (re->result != NULL) {
- dst_rectf = re->result->rectf;
+ dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf;
if (dst_rectf == NULL) {
RenderLayer *rl;
rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- dst_rectf = rl->rectf;
+ dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
}
}
@@ -727,9 +815,8 @@ static void render_result_rescale(Render *re)
}
}
}
+ render_result_free(result);
}
-
- render_result_free(result);
}
void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect)
@@ -776,6 +863,10 @@ void render_update_anim_renderdata(Render *re, RenderData *rd)
/* render layers */
BLI_freelistN(&re->r.layers);
BLI_duplicatelist(&re->r.layers, &rd->layers);
+
+ /* render views */
+ BLI_freelistN(&re->r.views);
+ BLI_duplicatelist(&re->r.views, &rd->views);
}
void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
@@ -908,9 +999,9 @@ static void *do_part_thread(void *pa_v)
if (R.test_break(R.tbh) == 0) {
if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
- pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM);
+ pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname);
else
- pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS);
+ pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname);
/* Copy EXR tile settings, so pipeline knows whether this is a result
* for Save Buffers enabled rendering.
@@ -933,7 +1024,7 @@ static void *do_part_thread(void *pa_v)
/* merge too on break! */
if (R.result->do_exr_tile) {
- render_result_exr_file_merge(R.result, pa->result);
+ render_result_exr_file_merge(R.result, pa->result, R.viewname);
}
else if (render_display_update_enabled(&R)) {
/* on break, don't merge in result for preview renders, looks nicer */
@@ -1029,13 +1120,28 @@ static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewpl
return found;
}
-static RenderPart *find_next_part(Render *re, int minx)
+typedef struct SortRenderPart {
+ RenderPart *pa;
+ long long int dist;
+} SortRenderPart;
+
+static int sort_render_part(const void *pa1, const void *pa2) {
+ const SortRenderPart *rpa1 = pa1;
+ const SortRenderPart *rpa2 = pa2;
+
+ if (rpa1->dist > rpa2->dist) return 1;
+ else if (rpa1->dist < rpa2->dist) return -1;
+
+ return 0;
+}
+
+static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue)
{
- RenderPart *pa, *best = NULL;
+ RenderPart *pa;
/* long long int's needed because of overflow [#24414] */
long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1;
- long long int mindist = (long long int)re->winx * (long long int)re->winy;
+ int totsort = 0;
/* find center of rendered parts, image center counts for 1 too */
for (pa = re->parts.first; pa; pa = pa->next) {
@@ -1044,31 +1150,48 @@ static RenderPart *find_next_part(Render *re, int minx)
centy += BLI_rcti_cent_y(&pa->disprect);
tot++;
}
+ else if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
+ if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
+ totsort++;
+ }
+ }
}
centx /= tot;
centy /= tot;
- /* closest of the non-rendering parts */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
- long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
- distx = (long long int)sqrt(distx * distx + disty * disty);
- if (distx < mindist) {
- if (re->r.mode & R_PANORAMA) {
- if (pa->disprect.xmin == minx) {
- best = pa;
- mindist = distx;
- }
- }
- else {
- best = pa;
- mindist = distx;
+ if (totsort > 0) {
+ SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort");
+ long int i = 0;
+
+ /* prepare the list */
+ for (pa = re->parts.first; pa; pa = pa->next) {
+ if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
+ if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
+ long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
+ long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
+ sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty);
+ sortlist[i].pa = pa;
+ i++;
}
}
}
+
+ /* Now sort it */
+ qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part);
+
+ /* Finally flush it to the workqueue */
+ for (i = 0; i < totsort; i++) {
+ pa = sortlist[i].pa;
+ pa->nr = i + 1; /* for nicest part, and for stats */
+ BLI_thread_queue_push(workqueue, pa);
+ }
+
+ MEM_freeN(sortlist);
+
+ return totsort;
}
- return best;
+
+ return 0;
}
static void print_part_stats(Render *re, RenderPart *pa)
@@ -1113,16 +1236,23 @@ static void *do_render_thread(void *thread_v)
return NULL;
}
-static void threaded_tile_processor(Render *re)
+static void main_render_result_end(Render *re)
+{
+ if (re->result->do_exr_tile) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_end(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+
+ if (re->r.scemode & R_EXR_CACHE_FILE) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_cache_write(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+}
+
+static void main_render_result_new(Render *re)
{
- RenderThread thread[BLENDER_MAX_THREADS];
- ThreadQueue *workqueue, *donequeue;
- ListBase threads;
- RenderPart *pa;
- rctf viewplane = re->viewplane;
- double lastdraw, elapsed, redrawtime = 1.0f;
- int totpart = 0, minx = 0, slice = 0, a, wait;
-
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* first step; free the entire render result, make new, and/or prepare exr buffer saving */
@@ -1130,25 +1260,35 @@ static void threaded_tile_processor(Render *re)
render_result_free(re->result);
if (re->sss_points && render_display_update_enabled(re))
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
else if (re->r.scemode & R_FULL_SAMPLE)
- re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR);
+ re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS);
else
re->result = render_result_new(re, &re->disprect, 0,
- (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS);
+ (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
}
BLI_rw_mutex_unlock(&re->resultmutex);
+
+ if (re->result->do_exr_tile)
+ render_result_exr_file_begin(re);
+}
+
+static void threaded_tile_processor(Render *re)
+{
+ RenderThread thread[BLENDER_MAX_THREADS];
+ ThreadQueue *workqueue, *donequeue;
+ ListBase threads;
+ RenderPart *pa;
+ rctf viewplane = re->viewplane;
+ double lastdraw, elapsed, redrawtime = 1.0f;
+ int totpart = 0, minx = 0, slice = 0, a, wait;
if (re->result == NULL)
return;
/* warning; no return here without closing exr file */
-
RE_parts_init(re, true);
-
- if (re->result->do_exr_tile)
- render_result_exr_file_begin(re);
/* assuming no new data gets added to dbase... */
R = *re;
@@ -1163,11 +1303,7 @@ static void threaded_tile_processor(Render *re)
/* for panorama we loop over slices */
while (find_next_pano_slice(re, &slice, &minx, &viewplane)) {
/* gather parts into queue */
- while ((pa = find_next_part(re, minx))) {
- pa->nr = totpart + 1; /* for nicest part, and for stats */
- totpart++;
- BLI_thread_queue_push(workqueue, pa);
- }
+ totpart = sort_and_queue_parts(re, minx, workqueue);
BLI_thread_queue_nowait(workqueue);
@@ -1253,27 +1389,23 @@ static void threaded_tile_processor(Render *re)
BLI_thread_queue_free(donequeue);
BLI_thread_queue_free(workqueue);
-
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
- if (re->r.scemode & R_EXR_CACHE_FILE) {
+ if (re->result->do_exr_tile) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_cache_write(re);
+ render_result_save_empty_result_tiles(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* unset threadsafety */
g_break = 0;
-
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
re->viewplane = viewplane; /* restore viewplane, modified by pano render */
}
#ifdef WITH_FREESTYLE
+static void init_freestyle(Render *re);
static void add_freestyle(Render *re, int render);
static void free_all_freestyle_renders(void);
#endif
@@ -1281,6 +1413,7 @@ static void free_all_freestyle_renders(void);
/* currently only called by preview renders and envmap */
void RE_TileProcessor(Render *re)
{
+ main_render_result_new(re);
threaded_tile_processor(re);
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -1290,8 +1423,8 @@ void RE_TileProcessor(Render *re)
/* Freestyle */
if (re->r.mode & R_EDGE_FRS) {
if (!re->test_break(re->tbh)) {
+ init_freestyle(re);
add_freestyle(re, 1);
-
free_all_freestyle_renders();
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -1306,6 +1439,7 @@ void RE_TileProcessor(Render *re)
static void do_render_3d(Render *re)
{
+ RenderView *rv;
int cfra_backup;
re->current_scene_update(re->suh, re->scene);
@@ -1322,40 +1456,55 @@ static void do_render_3d(Render *re)
BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs);
- /* lock drawing in UI during data phase */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 1);
-
- /* make render verts/faces/halos/lamps */
- if (render_scene_needs_vector(re)) {
- RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
- }
- else {
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
+ /* init main render result */
+ main_render_result_new(re);
+
+#ifdef WITH_FREESTYLE
+ if (re->r.mode & R_EDGE_FRS) {
+ init_freestyle(re);
}
+#endif
+
+ /* we need a new database for each view */
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ RE_SetActiveRenderView(re, rv->name);
+
+ /* lock drawing in UI during data phase */
+ if (re->draw_lock)
+ re->draw_lock(re->dlh, 1);
+
+ /* make render verts/faces/halos/lamps */
+ if (render_scene_needs_vector(re))
+ RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
+ else {
+ RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
+ RE_Database_Preprocess(re);
+ }
- /* clear UI drawing locks */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 0);
+ /* clear UI drawing locks */
+ if (re->draw_lock)
+ re->draw_lock(re->dlh, 0);
- threaded_tile_processor(re);
+ threaded_tile_processor(re);
#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS)
- if (!re->test_break(re->tbh))
- add_freestyle(re, 1);
+ /* Freestyle */
+ if (re->r.mode & R_EDGE_FRS)
+ if (!re->test_break(re->tbh))
+ add_freestyle(re, 1);
#endif
- /* do left-over 3d post effects (flares) */
- if (re->flag & R_HALO)
- if (!re->test_break(re->tbh))
- add_halo_flare(re);
-
- /* free all render verts etc */
- RE_Database_Free(re);
-
+ /* do left-over 3d post effects (flares) */
+ if (re->flag & R_HALO)
+ if (!re->test_break(re->tbh))
+ add_halo_flare(re);
+
+ /* free all render verts etc */
+ RE_Database_Free(re);
+ }
+
+ main_render_result_end(re);
+
re->scene->r.cfra = cfra_backup;
re->scene->r.subframe = 0.f;
}
@@ -1428,19 +1577,13 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b
rl1 = brr->layers.first;
for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) {
-
- /* combined */
- if (rl->rectf && rl1->rectf) {
- if (key_alpha)
- addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac);
- else
- addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
- }
-
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
+ if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha)
+ addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac);
+ else
+ addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
}
}
}
@@ -1453,7 +1596,7 @@ static void do_render_blur_3d(Render *re)
int blur = re->r.mblur_samples;
/* create accumulation render result */
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
/* do the blur steps */
while (blur--) {
@@ -1515,10 +1658,6 @@ static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, Rende
rl2 = rr2->layers.first;
for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) {
- /* combined */
- if (rl->rectf && rl1->rectf && rl2->rectf)
- interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4);
-
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
rpass2 = rl2->passes.first;
@@ -1586,7 +1725,7 @@ static void do_render_fields_3d(Render *re)
re->disprect.ymax *= 2;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
if (rr2) {
if (re->r.mode & R_ODDFIELD)
@@ -1658,7 +1797,7 @@ static void do_render_fields_blur_3d(Render *re)
/* weak is: it chances disprect from border */
render_result_disprect_to_full_resolution(re);
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
render_result_merge(rres, re->result);
render_result_free(re->result);
@@ -1953,7 +2092,7 @@ static void ntree_render_scenes(Render *re)
}
/* bad call... need to think over proper method still */
-static void render_composit_stats(void *UNUSED(arg), char *str)
+static void render_composit_stats(void *UNUSED(arg), const char *str)
{
R.i.infostr = str;
R.stats_draw(R.sdh, &R.i);
@@ -1961,6 +2100,23 @@ static void render_composit_stats(void *UNUSED(arg), char *str)
}
#ifdef WITH_FREESTYLE
+/* init Freestyle renderer */
+static void init_freestyle(Render *re)
+{
+ re->freestyle_bmain = BKE_main_new();
+
+ /* We use the same window manager for freestyle bmain as
+ * real bmain uses. This is needed because freestyle's
+ * bmain could be used to tag scenes for update, which
+ * implies call of ED_render_scene_update in some cases
+ * and that function requires proper window manager
+ * to present (sergey)
+ */
+ re->freestyle_bmain->wm = re->main->wm;
+
+ FRS_init_stroke_renderer(re);
+}
+
/* invokes Freestyle stroke rendering */
static void add_freestyle(Render *re, int render)
{
@@ -1971,18 +2127,7 @@ static void add_freestyle(Render *re, int render)
actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
- re->freestyle_bmain = BKE_main_new();
-
- /* We use the same window manager for freestyle bmain as
- * real bmain uses. This is needed because freestyle's
- * bmain could be used to tag scenes for update, which
- * implies call of ED_render_scene_update in some cases
- * and that function requires proper window manager
- * to present (sergey)
- */
- re->freestyle_bmain->wm = re->main->wm;
-
- FRS_init_stroke_rendering(re);
+ FRS_begin_stroke_rendering(re);
for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
if (do_link) {
@@ -1998,7 +2143,7 @@ static void add_freestyle(Render *re, int render)
}
}
- FRS_finish_stroke_rendering(re);
+ FRS_end_stroke_rendering(re);
/* restore the global R value (invalidated by nested execution of the internal renderer) */
R = *re;
@@ -2008,28 +2153,32 @@ static void add_freestyle(Render *re, int render)
static void composite_freestyle_renders(Render *re, int sample)
{
Render *freestyle_render;
+ RenderView *rv;
SceneRenderLayer *srl, *actsrl;
LinkData *link;
actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
link = (LinkData *)re->freestyle_renders.first;
- for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) {
- if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
- continue;
- if (FRS_is_freestyle_enabled(srl)) {
- freestyle_render = (Render *)link->data;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
+ if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
+ continue;
- /* may be NULL in case of empty render layer */
- if (freestyle_render) {
- render_result_exr_file_read_sample(freestyle_render, sample);
- FRS_composite_result(re, srl, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
+ if (FRS_is_freestyle_enabled(srl)) {
+ freestyle_render = (Render *)link->data;
+
+ /* may be NULL in case of empty render layer */
+ if (freestyle_render) {
+ render_result_exr_file_read_sample(freestyle_render, sample);
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
}
+ link = link->next;
}
- link = link->next;
}
}
@@ -2056,7 +2205,7 @@ static void free_all_freestyle_renders(void)
/* detach the window manager from freestyle bmain (see comments
* in add_freestyle() for more detail)
*/
- re1->freestyle_bmain->wm.first = re1->freestyle_bmain->wm.last = NULL;
+ BLI_listbase_clear(&re1->freestyle_bmain->wm);
BKE_main_free(re1->freestyle_bmain);
re1->freestyle_bmain = NULL;
@@ -2065,11 +2214,14 @@ static void free_all_freestyle_renders(void)
}
#endif
-/* reads all buffers, calls optional composite, merges in first result->rectf */
+/* reads all buffers, calls optional composite, merges in first result->views rectf */
static void do_merge_fullsample(Render *re, bNodeTree *ntree)
{
+ ListBase *rectfs;
+ RenderView *rv;
float *rectf, filt[3][3];
int x, y, sample;
+ int nr, numviews;
/* interaction callbacks */
if (ntree) {
@@ -2084,9 +2236,18 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
/* filtmask needs it */
R = *re;
- /* we accumulate in here */
- rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
-
+ /* temporary storage of the acccumulation buffers */
+ rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers");
+
+ numviews = BLI_listbase_count(&re->result->views);
+ for (nr = 0; nr < numviews; nr++) {
+ rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
+
+ /* we accumulate in here */
+ rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
+ BLI_addtail(rectfs, rv);
+ }
+
for (sample = 0; sample < re->r.osa; sample++) {
Scene *sce;
Render *re1;
@@ -2123,54 +2284,70 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
if (ntree) {
ntreeCompositTagRender(re->scene);
ntreeCompositTagAnimated(ntree);
-
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings);
+
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
+ }
}
-
- /* ensure we get either composited result or the active layer */
- RE_AcquireResultImage(re, &rres);
-
- /* accumulate with filter, and clip */
- mask = (1 << sample);
- mask_array(mask, filt);
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
- float *col = rres.rectf + 4 * y * re->rectx;
-
- for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
- /* clamping to 1.0 is needed for correct AA */
- if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f;
- if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f;
- if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f;
+ for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) {
+ rectf = rv->rectf;
+
+ /* ensure we get either composited result or the active layer */
+ RE_AcquireResultImage(re, &rres, nr);
+
+ /* accumulate with filter, and clip */
+ mask = (1 << sample);
+ mask_array(mask, filt);
+
+ for (y = 0; y < re->recty; y++) {
+ float *rf = rectf + 4 * y * re->rectx;
+ float *col = rres.rectf + 4 * y * re->rectx;
- add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
+ /* clamping to 1.0 is needed for correct AA */
+ CLAMP(col[0], 0.0f, 1.0f);
+ CLAMP(col[1], 0.0f, 1.0f);
+ CLAMP(col[2], 0.0f, 1.0f);
+
+ add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ }
}
- }
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImage(re);
- /* show stuff */
- if (sample != re->osa - 1) {
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- re->display_update(re->duh, re->result, NULL);
+ /* show stuff */
+ if (sample != re->osa - 1) {
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay = render_get_active_layer(re, re->result);
+ RE_SetActiveRenderView(re, rv->name);
+ re->display_update(re->duh, re->result, NULL);
+ }
}
-
- if (re->test_break(re->tbh))
- break;
}
- /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
+ for (nr = 0; nr < numviews; nr++) {
+ rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
+
+ /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
+ for (y = 0; y < re->recty; y++) {
+ float *rf = rectf + 4 * y * re->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4) {
- rf[0] = MAX2(rf[0], 0.0f);
- rf[1] = MAX2(rf[1], 0.0f);
- rf[2] = MAX2(rf[2], 0.0f);
- CLAMP(rf[3], 0.0f, 1.0f);
+ for (x = 0; x < re->rectx; x++, rf += 4) {
+ rf[0] = MAX2(rf[0], 0.0f);
+ rf[1] = MAX2(rf[1], 0.0f);
+ rf[2] = MAX2(rf[2], 0.0f);
+ CLAMP(rf[3], 0.0f, 1.0f);
+ }
}
+
+ /* store the final result */
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ rv = RE_RenderViewGetById(re->result, nr);
+ if (rv->rectf)
+ MEM_freeN(rv->rectf);
+ rv->rectf = rectf;
+ BLI_rw_mutex_unlock(&re->resultmutex);
}
/* clear interaction callbacks */
@@ -2183,12 +2360,14 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
/* disable full sample print */
R.i.curfsa = 0;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- if (re->result->rectf)
- MEM_freeN(re->result->rectf);
- re->result->rectf = rectf;
- BLI_rw_mutex_unlock(&re->resultmutex);
+
+ /* garbage collection */
+ while (rectfs->first) {
+ RenderView *rv = rectfs->first;
+ BLI_remlink(rectfs, rv);
+ MEM_freeN(rv);
+ }
+ MEM_freeN(rectfs);
}
/* called externally, via compositor */
@@ -2241,8 +2420,10 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
re->display_clear(re->dch, re->result);
#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS)
+ if (re->r.mode & R_EDGE_FRS) {
+ init_freestyle(re);
add_freestyle(re, 0);
+ }
#endif
do_merge_fullsample(re, ntree);
@@ -2264,7 +2445,11 @@ static void do_render_composite_fields_blur_3d(Render *re)
if (composite_needs_render(re->scene, 1)) {
/* save memory... free all cached images */
ntreeFreeCache(ntree);
-
+
+ /* render the frames
+ * it could be optimized to render only the needed view
+ * but what if a scene has a different number of views
+ * than the main scene? */
do_render_fields_blur_3d(re);
}
else {
@@ -2277,7 +2462,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
if ((re->r.mode & R_CROP) == 0) {
render_result_disprect_to_full_resolution(re);
}
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -2315,6 +2500,8 @@ static void do_render_composite_fields_blur_3d(Render *re)
/* in case it was never initialized */
R.sdh = re->sdh;
R.stats_draw = re->stats_draw;
+ R.i.starttime = re->i.starttime;
+ R.i.cfra = re->i.cfra;
if (update_newframe)
BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
@@ -2322,7 +2509,10 @@ static void do_render_composite_fields_blur_3d(Render *re)
if (re->r.scemode & R_FULL_SAMPLE)
do_merge_fullsample(re, ntree);
else {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings);
+ RenderView *rv;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
+ }
}
ntree->stats_draw = NULL;
@@ -2347,13 +2537,17 @@ static void do_render_composite_fields_blur_3d(Render *re)
static void renderresult_stampinfo(Render *re)
{
RenderResult rres;
+ RenderView *rv;
+ int nr;
/* this is the basic trick to get the displayed float or char rect from render result */
- RE_AcquireResultImage(re, &rres);
- BKE_image_stamp_buf(
- re->scene, RE_GetCamera(re),
- (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
- RE_ReleaseResultImage(re);
+ nr = 0;
+ for (rv = re->result->views.first;rv;rv = rv->next, nr++) {
+ RE_SetActiveRenderView(re, rv->name);
+ RE_AcquireResultImage(re, &rres, nr);
+ BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+ RE_ReleaseResultImage(re);
+ }
}
int RE_seq_render_active(Scene *scene, RenderData *rd)
@@ -2377,10 +2571,12 @@ int RE_seq_render_active(Scene *scene, RenderData *rd)
static void do_render_seq(Render *re)
{
static int recurs_depth = 0;
- struct ImBuf *ibuf, *out;
+ struct ImBuf *out;
RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */
int cfra = re->r.cfra;
SeqRenderData context;
+ size_t view_id, tot_views;
+ struct ImBuf **ibuf_arr;
int re_x, re_y;
re->i.cfra = cfra;
@@ -2403,45 +2599,67 @@ static void do_render_seq(Render *re)
re_y = re->result->recty;
}
+ tot_views = BKE_scene_multiview_num_views_get(&re->r);
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs");
+
BKE_sequencer_new_render_data(
re->eval_ctx, re->main, re->scene,
re_x, re_y, 100,
&context);
- out = BKE_sequencer_give_ibuf(&context, cfra, 0);
+ /* the renderresult gets destroyed during the rendering, so we first collect all ibufs
+ * and then we populate the final renderesult */
- if (out) {
- ibuf = IMB_dupImBuf(out);
- IMB_freeImBuf(out);
- BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf);
- }
- else {
- ibuf = NULL;
- }
+ for (view_id = 0; view_id < tot_views; view_id++) {
+ context.view_id = view_id;
+ out = BKE_sequencer_give_ibuf(&context, cfra, 0);
- recurs_depth--;
+ if (out) {
+ ibuf_arr[view_id] = IMB_dupImBuf(out);
+ IMB_freeImBuf(out);
+ BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf_arr[view_id]);
+ }
+ else {
+ ibuf_arr[view_id] = NULL;
+ }
+ }
rr = re->result;
-
+
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_views_new(rr, &re->r);
+ BLI_rw_mutex_unlock(&re->resultmutex);
- if (ibuf) {
- /* copy ibuf into combined pixel rect */
- render_result_rect_from_ibuf(rr, &re->r, ibuf);
-
- if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
- Editing *ed = re->scene->ed;
- if (ed)
- BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true);
+ for (view_id = 0; view_id < tot_views; view_id++) {
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
+ if (ibuf_arr[view_id]) {
+ /* copy ibuf into combined pixel rect */
+ render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id);
+
+ if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
+ Editing *ed = re->scene->ed;
+ if (ed)
+ BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true);
+ }
+ IMB_freeImBuf(ibuf_arr[view_id]);
}
- IMB_freeImBuf(ibuf);
- }
- else {
- /* render result is delivered empty in most cases, nevertheless we handle all cases */
- render_result_rect_fill_zero(rr);
+ else {
+ /* render result is delivered empty in most cases, nevertheless we handle all cases */
+ render_result_rect_fill_zero(rr, view_id);
+ }
+
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ /* would mark display buffers as invalid */
+ RE_SetActiveRenderView(re, rv->name);
+ re->display_update(re->duh, re->result, NULL);
}
- BLI_rw_mutex_unlock(&re->resultmutex);
+ MEM_freeN(ibuf_arr);
+
+ recurs_depth--;
/* just in case this flag went missing at some point */
re->r.scemode |= R_DOSEQ;
@@ -2451,9 +2669,6 @@ static void do_render_seq(Render *re)
re->progress(re->prh, (float)(cfra - re->r.sfra) / (re->r.efra - re->r.sfra));
else
re->progress(re->prh, 1.0f);
-
- /* would mark display buffers as invalid */
- re->display_update(re->duh, re->result, NULL);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -2461,6 +2676,8 @@ static void do_render_seq(Render *re)
/* main loop: doing sequence + fields + blur + 3d render + compositing */
static void do_render_all_options(Render *re)
{
+ Object *camera;
+
re->current_scene_update(re->suh, re->scene);
BKE_scene_camera_switch_update(re->scene);
@@ -2494,6 +2711,10 @@ static void do_render_all_options(Render *re)
re->stats_draw(re->sdh, &re->i);
+ /* save render result stamp if needed */
+ camera = RE_GetCamera(re);
+ BKE_render_result_stamp_info(re->scene, camera, re->result);
+
/* stamp image info here */
if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
renderresult_stampinfo(re);
@@ -2540,11 +2761,50 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override
}
}
+static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports)
+{
+ SceneRenderView *srv;
+ bool active_view = false;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ active_view = true;
+
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ Object *view_camera;
+ view_camera = BKE_camera_multiview_render(scene, camera, srv->name);
+
+ if (view_camera == camera) {
+ /* if the suffix is not in the camera, means we are using the fallback camera */
+ if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) {
+ BKE_reportf(reports, RPT_ERROR, "Camera \"%s\" is not a multi-view camera",
+ camera->id.name + 2);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (!active_view) {
+ BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2);
+ return false;
+ }
+
+ return true;
+}
+
static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
{
if (camera_override == NULL && scene->camera == NULL)
scene->camera = BKE_scene_camera_find(scene);
+ if (!check_valid_camera_multiview(scene, scene->camera, reports))
+ return false;
+
if (RE_seq_render_active(scene, &scene->r)) {
if (scene->ed) {
Sequence *seq = scene->ed->seqbase.first;
@@ -2562,6 +2822,8 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
}
}
}
+ else if (!check_valid_camera_multiview(seq->scene, seq->scene_camera, reports))
+ return false;
}
seq = seq->next;
@@ -2726,6 +2988,17 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init)
BKE_ptcache_bake(&baker);
}
+
+void RE_SetActiveRenderView(Render *re, const char *viewname)
+{
+ BLI_strncpy(re->viewname, viewname, sizeof(re->viewname));
+}
+
+const char *RE_GetActiveRenderView(Render *re)
+{
+ return re->viewname;
+}
+
/* evaluating scene options for general Blender render */
static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl,
Object *camera_override, unsigned int lay_override, int anim, int anim_init)
@@ -2761,7 +3034,8 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->lay = lay_override ? lay_override : scene->lay;
re->layer_override = lay_override;
re->i.localview = (re->lay & 0xFF000000) != 0;
-
+ re->viewname[0] = '\0';
+
/* not too nice, but it survives anim-border render */
if (anim) {
render_update_anim_renderdata(re, &scene->r);
@@ -2835,10 +3109,10 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
char name[FILE_MAX];
BKE_image_path_from_imformat(
name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
/* reports only used for Movie */
- do_write_image_or_movie(re, bmain, scene, NULL, name);
+ do_write_image_or_movie(re, bmain, scene, NULL, 0, name);
}
}
@@ -2870,109 +3144,284 @@ void RE_RenderFreestyleExternal(Render *re)
if (!re->test_break(re->tbh)) {
RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
RE_Database_Preprocess(re);
+ init_freestyle(re);
add_freestyle(re, 1);
RE_Database_Free(re);
}
}
#endif
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override)
+bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name)
{
- char name[FILE_MAX];
- RenderResult rres;
- Object *camera = RE_GetCamera(re);
- double render_time;
- int ok = 1;
-
- RE_AcquireResultImage(re, &rres);
+ bool is_mono;
+ bool ok = true;
+ RenderData *rd = &scene->r;
- /* write movie or image */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- bool do_free = false;
- ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r);
+ if (!rr)
+ return false;
- /* note; the way it gets 32 bits rects is weak... */
- if (ibuf->rect == NULL) {
- ibuf->rect = MEM_mapallocN(sizeof(int) * rres.rectx * rres.recty, "temp 32 bits rect");
- ibuf->mall |= IB_rect;
- RE_AcquiredResultGet32(re, &rres, ibuf->rect);
- do_free = true;
- }
+ is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+ if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW)
+ {
+ RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL);
+ printf("Saved: %s\n", name);
+ }
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
+ /* mono, legacy code */
+ else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL))
+ {
+ RenderView *rv;
+ size_t view_id;
+ char filepath[FILE_MAX];
- ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect,
- ibuf->x, ibuf->y, re->reports);
- if (do_free) {
- MEM_freeN(ibuf->rect);
- ibuf->rect = NULL;
- ibuf->mall &= ~IB_rect;
- }
+ BLI_strncpy(filepath, name, sizeof(filepath));
- /* imbuf knows which rects are not part of ibuf */
- IMB_freeImBuf(ibuf);
+ for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) {
+ if (!is_mono) {
+ BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name);
+ }
- printf("Append frame %d", scene->r.cfra);
- }
- else {
- if (name_override)
- BLI_strncpy(name, name_override, sizeof(name));
- else
- BKE_image_path_from_imformat(
- name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
-
- if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- if (re->result) {
- RE_WriteRenderResult(re->reports, re->result, name, scene->r.im_format.exr_codec);
- printf("Saved: %s", name);
+ if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name);
+ printf("Saved: %s\n", name);
+ }
+ else {
+ ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id);
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &rd->im_format);
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, &rd->im_format);
+ }
+
+ if (ok == false) {
+ printf("Render error: cannot save %s\n", name);
+ }
+ else printf("Saved: %s\n", name);
+
+ /* optional preview images for exr */
+ if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ ImageFormatData imf = rd->im_format;
+ imf.imtype = R_IMF_IMTYPE_JPEG90;
+
+ if (BLI_testextensie(name, ".exr"))
+ name[strlen(name) - 4] = 0;
+ BKE_image_path_ensure_ext_from_imformat(name, &imf);
+ ibuf->planes = 24;
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &imf);
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &imf);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, &imf);
+ }
+ printf("Saved: %s\n", name);
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf);
}
}
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D);
+
+ if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ printf("Stereo 3D not support for MultiLayer image: %s\n", name);
+ }
else {
- ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r);
+ ImBuf *ibuf_arr[3] = {NULL};
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id);
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+ IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
+ }
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
- ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format);
-
- if (ok == 0) {
+ if (stamp)
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
+ else
+ ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format);
+
+ if (ok == false)
printf("Render error: cannot save %s\n", name);
- }
- else printf("Saved: %s", name);
-
+ else
+ printf("Saved: %s\n", name);
+
/* optional preview images for exr */
- if (ok && scene->r.im_format.imtype == R_IMF_IMTYPE_OPENEXR && (scene->r.im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = scene->r.im_format;
+ if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR &&
+ (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG))
+ {
+ ImageFormatData imf = rd->im_format;
imf.imtype = R_IMF_IMTYPE_JPEG90;
if (BLI_testextensie(name, ".exr"))
name[strlen(name) - 4] = 0;
+
BKE_image_path_ensure_ext_from_imformat(name, &imf);
- ibuf->planes = 24;
+ ibuf_arr[2]->planes = 24;
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings,
&scene->display_settings, &imf);
- BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf);
- printf("\nSaved: %s", name);
+ if (stamp)
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
+ else
+ ok = BKE_imbuf_write(ibuf_arr[2], name, &imf);
+
+ printf("Saved: %s\n", name);
}
-
+
+ /* imbuf knows which rects are not part of ibuf */
+ for (i = 0; i < 3; i++) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ return ok;
+}
+
+bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh,
+ const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos, bool preview)
+{
+ bool is_mono;
+ bool ok = true;
+
+ if (!rr)
+ return false;
+
+ is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+
+ if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ size_t view_id;
+ for (view_id = 0; view_id < totvideos; view_id++) {
+ bool do_free = false;
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id);
+
+ /* note; the way it gets 32 bits rects is weak... */
+ if (ibuf->rect == NULL) {
+ ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect");
+ ibuf->mall |= IB_rect;
+ render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
+ do_free = true;
+ }
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+
+ ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra,
+ (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports);
+
+ if (do_free) {
+ MEM_freeN(ibuf->rect);
+ ibuf->rect = NULL;
+ ibuf->mall &= ~IB_rect;
+ }
+
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf);
}
+ printf("Append frame %d\n", scene->r.cfra);
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ ImBuf *ibuf_arr[3] = {NULL};
+ bool do_free[2] = {false, false};
+ size_t i;
+
+ BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D));
+
+ for (i = 0; i < 2; i++) {
+ int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id);
+
+ /* note; the way it gets 32 bits rects is weak... */
+ if (ibuf_arr[i]->rect == NULL) {
+ ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect");
+ ibuf_arr[i]->mall |= IB_rect;
+ render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
+ do_free[i] = true;
+ }
+
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+ }
+
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
+
+ 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++) {
+ if (do_free[i]) {
+ MEM_freeN(ibuf_arr[i]->rect);
+ ibuf_arr[i]->rect = NULL;
+ ibuf_arr[i]->mall &= ~IB_rect;
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ return ok;
+}
+
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override)
+{
+ char name[FILE_MAX];
+ RenderResult rres;
+ double render_time;
+ bool ok = true;
+
+ RE_AcquireResultImageViews(re, &rres);
+
+ /* write movie or image */
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos, false);
+ }
+ else {
+ if (name_override)
+ BLI_strncpy(name, name_override, sizeof(name));
+ else
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
+
+ /* write images as individual images or stereo */
+ ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name);
}
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImageViews(re, &rres);
render_time = re->i.lastframetime;
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
BLI_timestr(re->i.lastframetime, name, sizeof(name));
printf(" Time: %s", name);
-
+
+ /* Flush stdout to be sure python callbacks are printing stuff after blender. */
+ fflush(stdout);
+
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS);
BLI_timestr(re->i.lastframetime - render_time, name, sizeof(name));
@@ -2984,20 +3433,51 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
return ok;
}
+static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height)
+{
+ size_t width, height;
+ if (re->r.mode & R_BORDER) {
+ if ((re->r.mode & R_CROP) == 0) {
+ width = re->winx;
+ height = re->winy;
+ }
+ else {
+ width = re->rectx;
+ height = re->recty;
+ }
+ }
+ else {
+ width = re->rectx;
+ height = re->recty;
+ }
+
+ BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height);
+}
+
/* saves images to disk */
void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override,
unsigned int lay_override, int sfra, int efra, int tfra)
{
RenderData rd = scene->r;
- bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ bMovieHandle *mh = NULL;
int cfrao = scene->r.cfra;
int nfra, totrendered = 0, totskipped = 0;
-
+ const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd);
+ const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
+ const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 &&
+ (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
+
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
/* do not fully call for each frame, it initializes & pops output window */
if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1))
return;
+
+ /* we don't support Frame Server and streaming of individual views */
+ if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) {
+ BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering");
+ return;
+ }
/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
/* is also set by caller renderwin.c */
@@ -3005,30 +3485,33 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
re->flag |= R_ANIMATION;
- if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- int width, height;
- if (re->r.mode & R_BORDER) {
- if ((re->r.mode & R_CROP) == 0) {
- width = re->winx;
- height = re->winy;
- }
- else {
- width = re->rectx;
- height = re->recty;
- }
- }
- else {
- width = re->rectx;
- height = re->recty;
- }
+ if (is_movie) {
+ size_t i, width, height;
+
+ get_videos_dimensions(re, &rd, &width, &height);
+
+ mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context");
+
+ for (i = 0; i < totvideos; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i);
- if (!mh->start_movie(scene, &re->r, width, height, re->reports))
- G.is_break = true;
+ re->movie_ctx_arr[i] = mh->context_create();
+
+ if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix))
+ G.is_break = true;
+ }
}
- if (mh->get_next_frame) {
+ if (mh && mh->get_next_frame) {
+ /* MULTIVIEW_TODO:
+ * in case a new video format is added that implements get_next_frame multiview has to be addressed
+ * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well
+ */
+ BLI_assert(totvideos < 2);
+
while (!(G.is_break == 1)) {
- int nf = mh->get_next_frame(&re->r, re->reports);
+ int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports);
if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
scene->r.cfra = re->r.cfra = nf;
@@ -3038,7 +3521,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
totrendered++;
if (re->test_break(re->tbh) == 0) {
- if (!do_write_image_or_movie(re, bmain, scene, mh, NULL))
+ if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
G.is_break = true;
}
@@ -3081,20 +3564,67 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
nfra += tfra;
/* Touch/NoOverwrite options are only valid for image's */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
+ if (is_movie == false) {
if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH))
BKE_image_path_from_imformat(
name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
+
+ if (scene->r.mode & R_NO_OVERWRITE) {
+ if (!is_multiview_name) {
+ if (BLI_exists(name)) {
+ printf("skipping existing frame \"%s\"\n", name);
+ totskipped++;
+ continue;
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ bool is_skip = false;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
- if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) {
- printf("skipping existing frame \"%s\"\n", name);
- totskipped++;
- continue;
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if (BLI_exists(filepath)) {
+ is_skip = true;
+ printf("skipping existing frame \"%s\" for view \"%s\"\n", filepath, srv->name);
+ }
+ }
+
+ if (is_skip) {
+ totskipped++;
+ continue;
+ }
+ }
}
- if (scene->r.mode & R_TOUCH && !BLI_exists(name)) {
- BLI_make_existing_file(name); /* makes the dir if its not there */
- BLI_file_touch(name);
+
+ if (scene->r.mode & R_TOUCH) {
+ if (!is_multiview_name) {
+ if (!BLI_exists(name)) {
+ BLI_make_existing_file(name); /* makes the dir if its not there */
+ BLI_file_touch(name);
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
+
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if (!BLI_exists(filepath)) {
+ BLI_make_existing_file(filepath); /* makes the dir if its not there */
+ BLI_file_touch(filepath);
+ }
+ }
+ }
}
}
@@ -3109,7 +3639,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
if (re->test_break(re->tbh) == 0) {
if (!G.is_break)
- if (!do_write_image_or_movie(re, bmain, scene, mh, NULL))
+ if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
G.is_break = true;
}
else
@@ -3117,10 +3647,30 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
if (G.is_break == true) {
/* remove touched file */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
- if ((scene->r.mode & R_TOUCH) && (BLI_file_size(name) == 0)) {
- /* BLI_exists(name) is implicit */
- BLI_delete(name, false, false);
+ if (is_movie == false) {
+ if ((scene->r.mode & R_TOUCH)) {
+ if (!is_multiview_name) {
+ if ((BLI_file_size(name) == 0)) {
+ /* BLI_exists(name) is implicit */
+ BLI_delete(name, false, false);
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
+
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if ((BLI_file_size(filepath) == 0)) {
+ /* BLI_exists(filepath) is implicit */
+ BLI_delete(filepath, false, false);
+ }
+ }
+ }
}
}
@@ -3135,8 +3685,17 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
}
/* end movie */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype))
- mh->end_movie();
+ if (is_movie) {
+ size_t i;
+ for (i = 0; i < totvideos; i++) {
+ mh->end_movie(re->movie_ctx_arr[i]);
+ mh->context_free(re->movie_ctx_arr[i]);
+ }
+
+ if (re->movie_ctx_arr) {
+ MEM_freeN(re->movie_ctx_arr);
+ }
+ }
if (totskipped && totrendered == 0)
BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
@@ -3234,13 +3793,22 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
{
/* OCIO_TODO: assume layer was saved in defaule color space */
ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL);
+ RenderPass *rpass = NULL;
+
+ /* 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)
+ break;
+
+ if (rpass == NULL)
+ BKE_reportf(reports, RPT_ERROR, "%s: no Combined pass found in the render layer '%s'", __func__, filename);
if (ibuf && (ibuf->rect || ibuf->rect_float)) {
if (ibuf->x == layer->rectx && ibuf->y == layer->recty) {
if (ibuf->rect_float == NULL)
IMB_float_from_rect(ibuf);
- memcpy(layer->rectf, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
+ memcpy(rpass->rect, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
}
else {
if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) {
@@ -3253,29 +3821,29 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
if (ibuf_clip) {
IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty);
- memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
+ memcpy(rpass->rect, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
IMB_freeImBuf(ibuf_clip);
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to allocate clip buffer '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filename);
}
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: incorrect dimensions for partial copy '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: incorrect dimensions for partial copy '%s'", __func__, filename);
}
}
IMB_freeImBuf(ibuf);
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
}
}
void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename)
{
if (!render_result_exr_file_read_path(result, NULL, filename)) {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
return;
}
}
@@ -3341,3 +3909,35 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env,
}
}
+/* used in the interface to decide whether to show layers */
+bool RE_layers_have_name(struct RenderResult *rr)
+{
+ switch (BLI_listbase_count_ex(&rr->layers, 2)) {
+ case 0:
+ return false;
+ break;
+ case 1:
+ return (((RenderLayer *)rr->layers.first)->name[0] != '\0');
+ break;
+ default:
+ return true;
+ break;
+ }
+ return false;
+}
+
+RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+{
+ RenderPass *rp = NULL;
+
+ for (rp = rl->passes.last; rp; rp = rp->prev) {
+ if (rp->passtype == passtype) {
+
+ if (viewname == NULL || viewname[0] == '\0')
+ break;
+ else if (STREQ(rp->view, viewname))
+ break;
+ }
+ }
+ return rp;
+}
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 1f4726809de..3a1f1fbb744 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -68,25 +68,34 @@ extern struct Render R;
static int point_data_used(PointDensity *pd)
{
int pd_bitflag = 0;
-
+
if (pd->source == TEX_PD_PSYS) {
- if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED))
+ if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
+ (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
+ (pd->color_source == TEX_PD_COLOR_PARTVEL) ||
+ (pd->color_source == TEX_PD_COLOR_PARTSPEED))
+ {
pd_bitflag |= POINT_DATA_VEL;
- if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
+ }
+ if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
+ (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
+ (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
+ {
pd_bitflag |= POINT_DATA_LIFE;
+ }
}
-
+
return pd_bitflag;
}
-/* additional data stored alongside the point density BVH,
- * accessible by point index number to retrieve other information
+/* additional data stored alongside the point density BVH,
+ * accessible by point index number to retrieve other information
* such as particle velocity or lifetime */
static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
{
int data_size = 0;
-
+
if (point_data_used & POINT_DATA_VEL) {
/* store 3 channels of velocity data */
data_size += 3;
@@ -96,60 +105,69 @@ static void alloc_point_data(PointDensity *pd, int total_particles, int point_da
data_size += 1;
}
- if (data_size)
- pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data");
+ if (data_size) {
+ pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles,
+ "particle point data");
+ }
}
-static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
+static void pointdensity_cache_psys(Scene *scene,
+ PointDensity *pd,
+ Object *ob,
+ ParticleSystem *psys,
+ float viewmat[4][4],
+ float winmat[4][4],
+ int winx, int winy)
{
- DerivedMesh* dm;
+ DerivedMesh *dm;
ParticleKey state;
ParticleCacheKey *cache;
- ParticleSimulationData sim= {NULL};
- ParticleData *pa=NULL;
- float cfra = BKE_scene_frame_get(re->scene);
+ ParticleSimulationData sim = {NULL};
+ ParticleData *pa = NULL;
+ float cfra = BKE_scene_frame_get(scene);
int i /*, childexists*/ /* UNUSED */;
- int total_particles, offset=0;
+ int total_particles, offset = 0;
int data_used = point_data_used(pd);
float partco[3];
- float obview[4][4];
-
+
/* init everything */
- if (!psys || !ob || !pd) return;
+ if (!psys || !ob || !pd) {
+ return;
+ }
- mul_m4_m4m4(obview, ob->obmat, re->viewinv);
-
/* Just to create a valid rendering context for particles */
- psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
-
- dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
-
+ psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
+
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+
if ( !psys_check_enabled(ob, psys)) {
psys_render_restore(ob, psys);
return;
}
-
- sim.scene= re->scene;
- sim.ob= ob;
- sim.psys= psys;
+
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
/* in case ob->imat isn't up-to-date */
invert_m4_m4(ob->imat, ob->obmat);
-
- total_particles = psys->totpart+psys->totchild;
+
+ total_particles = psys->totpart + psys->totchild;
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
+
pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
alloc_point_data(pd, total_particles, data_used);
pd->totpoints = total_particles;
- if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
-
+ if (data_used & POINT_DATA_VEL) {
+ offset = pd->totpoints * 3;
+ }
+
#if 0 /* UNUSED */
if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
childexists = 1;
#endif
- for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {
+ for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
if (psys->part->type == PART_HAIR) {
/* hair particles */
@@ -175,19 +193,19 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa
if (data_used & POINT_DATA_LIFE) {
if (i < psys->totpart) {
- state.time = (cfra - pa->time)/pa->lifetime;
+ state.time = (cfra - pa->time) / pa->lifetime;
}
else {
- ChildParticle *cpa= (psys->child + i) - psys->totpart;
+ ChildParticle *cpa = (psys->child + i) - psys->totpart;
float pa_birthtime, pa_dietime;
-
+
state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
}
}
}
copy_v3_v3(partco, state.co);
-
+
if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
mul_m4_v3(ob->imat, partco);
else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
@@ -196,48 +214,50 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa
else {
/* TEX_PD_WORLDSPACE */
}
-
+
BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
-
+
if (data_used & POINT_DATA_VEL) {
- pd->point_data[i*3 + 0] = state.vel[0];
- pd->point_data[i*3 + 1] = state.vel[1];
- pd->point_data[i*3 + 2] = state.vel[2];
+ pd->point_data[i * 3 + 0] = state.vel[0];
+ pd->point_data[i * 3 + 1] = state.vel[1];
+ pd->point_data[i * 3 + 2] = state.vel[2];
}
if (data_used & POINT_DATA_LIFE) {
pd->point_data[offset + i] = state.time;
}
}
-
+
BLI_bvhtree_balance(pd->point_tree);
dm->release(dm);
-
+
if (psys->lattice_deform_data) {
end_latt_deform(psys->lattice_deform_data);
psys->lattice_deform_data = NULL;
}
-
+
psys_render_restore(ob, psys);
}
-static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
+static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob)
{
int i;
DerivedMesh *dm;
MVert *mvert = NULL;
-
- dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
- mvert= dm->getVertArray(dm); /* local object space */
-
- pd->totpoints= dm->getNumVerts(dm);
- if (pd->totpoints == 0) return;
+
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ mvert = dm->getVertArray(dm); /* local object space */
+
+ pd->totpoints = dm->getNumVerts(dm);
+ if (pd->totpoints == 0) {
+ return;
+ }
pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
-
- for (i=0; i < pd->totpoints; i++, mvert++) {
+
+ for (i = 0; i < pd->totpoints; i++, mvert++) {
float co[3];
-
+
copy_v3_v3(co, mvert->co);
switch (pd->ob_cache_space) {
@@ -255,47 +275,60 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
BLI_bvhtree_insert(pd->point_tree, i, co, 1);
}
-
+
BLI_bvhtree_balance(pd->point_tree);
dm->release(dm);
}
-void cache_pointdensity(Render *re, Tex *tex)
+
+static void cache_pointdensity_ex(Scene *scene,
+ PointDensity *pd,
+ float viewmat[4][4],
+ float winmat[4][4],
+ int winx, int winy)
{
- PointDensity *pd = tex->pd;
-
- if (!pd)
+ if (pd == NULL) {
return;
+ }
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
pd->point_tree = NULL;
}
-
+
if (pd->source == TEX_PD_PSYS) {
Object *ob = pd->object;
ParticleSystem *psys;
- if (!ob || !pd->psys) return;
+ if (!ob || !pd->psys) {
+ return;
+ }
- psys= BLI_findlink(&ob->particlesystem, pd->psys-1);
- if (!psys) return;
-
- pointdensity_cache_psys(re, pd, ob, psys);
+ psys = BLI_findlink(&ob->particlesystem, pd->psys - 1);
+ if (!psys) {
+ return;
+ }
+
+ pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy);
}
else if (pd->source == TEX_PD_OBJECT) {
Object *ob = pd->object;
if (ob && ob->type == OB_MESH)
- pointdensity_cache_object(re, pd, ob);
+ pointdensity_cache_object(scene, pd, ob);
}
}
-static void free_pointdensity(Render *UNUSED(re), Tex *tex)
+void cache_pointdensity(Render *re, PointDensity *pd)
{
- PointDensity *pd = tex->pd;
+ cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy);
+}
+
+void free_pointdensity(PointDensity *pd)
+{
+ if (pd == NULL) {
+ return;
+ }
- if (!pd) return;
-
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
pd->point_tree = NULL;
@@ -308,24 +341,23 @@ static void free_pointdensity(Render *UNUSED(re), Tex *tex)
pd->totpoints = 0;
}
-
-
void make_pointdensities(Render *re)
{
Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW)
+
+ if (re->scene->r.scemode & R_BUTS_PREVIEW) {
return;
-
+ }
+
re->i.infostr = IFACE_("Caching Point Densities");
re->stats_draw(re->sdh, &re->i);
- for (tex= re->main->tex.first; tex; tex= tex->id.next) {
- if (tex->id.us && tex->type==TEX_POINTDENSITY) {
- cache_pointdensity(re, tex);
+ for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
+ if (tex->id.us && tex->type == TEX_POINTDENSITY) {
+ cache_pointdensity(re, tex->pd);
}
}
-
+
re->i.infostr = NULL;
re->stats_draw(re->sdh, &re->i);
}
@@ -333,13 +365,13 @@ void make_pointdensities(Render *re)
void free_pointdensities(Render *re)
{
Tex *tex;
-
+
if (re->scene->r.scemode & R_BUTS_PREVIEW)
return;
-
- for (tex= re->main->tex.first; tex; tex= tex->id.next) {
- if (tex->id.us && tex->type==TEX_POINTDENSITY) {
- free_pointdensity(re, tex);
+
+ for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
+ if (tex->id.us && tex->type == TEX_POINTDENSITY) {
+ free_pointdensity(tex->pd);
}
}
}
@@ -364,20 +396,20 @@ static void accum_density(void *userdata, int index, float squared_dist)
PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
float density = 0.0f;
-
+
if (pdr->point_data_used & POINT_DATA_VEL) {
- pdr->vec[0] += pdr->point_data[index*3 + 0]; // * density;
- pdr->vec[1] += pdr->point_data[index*3 + 1]; // * density;
- pdr->vec[2] += pdr->point_data[index*3 + 2]; // * density;
+ pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density;
+ pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density;
+ pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density;
}
if (pdr->point_data_used & POINT_DATA_LIFE) {
*pdr->age += pdr->point_data[pdr->offset + index]; // * density;
}
-
+
if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
density = dist;
else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
- density = 3.0f*dist*dist - 2.0f*dist*dist*dist;
+ density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
density = pow(dist, pdr->softness);
else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
@@ -386,30 +418,30 @@ static void accum_density(void *userdata, int index, float squared_dist)
density = sqrtf(dist);
else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
if (pdr->point_data_used & POINT_DATA_LIFE)
- density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f);
+ density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f);
else
density = dist;
}
else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
if (pdr->point_data_used & POINT_DATA_VEL)
- density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale;
+ density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale;
else
density = dist;
}
-
+
if (pdr->density_curve && dist != 0.0f) {
curvemapping_initialize(pdr->density_curve);
- density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist;
+ density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
}
-
+
*pdr->density += density;
}
-static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
+static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
{
- pdr->squared_radius = pd->radius*pd->radius;
+ pdr->squared_radius = pd->radius * pd->radius;
pdr->density = density;
pdr->point_data = pd->point_data;
pdr->falloff_type = pd->falloff_type;
@@ -418,7 +450,7 @@ static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *
pdr->softness = pd->falloff_softness;
pdr->noise_influence = pd->noise_influence;
pdr->point_data_used = point_data_used(pd);
- pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0;
+ pdr->offset = (pdr->point_data_used & POINT_DATA_VEL) ? pd->totpoints * 3 : 0;
pdr->density_curve = density_curve;
pdr->velscale = velscale;
}
@@ -429,52 +461,56 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
int retval = TEX_INT;
PointDensity *pd = tex->pd;
PointDensityRangeData pdr;
- float density=0.0f, age=0.0f, time=0.0f;
+ float density = 0.0f, age = 0.0f, time = 0.0f;
float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
float col[4];
float turb, noise_fac;
- int num=0;
-
+ int num = 0;
+
texres->tin = 0.0f;
-
+
if ((!pd) || (!pd->point_tree))
return 0;
-
- init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
- (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f);
+
+ init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
+ (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
+ pd->falloff_speed_scale * 0.001f);
noise_fac = pd->noise_fac * 0.5f; /* better default */
-
+
copy_v3_v3(co, texvec);
-
+
if (point_data_used(pd)) {
/* does a BVH lookup to find accumulated density and additional point data *
* stores particle velocity vector in 'vec', and particle lifetime in 'time' */
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
if (num > 0) {
age /= num;
- mul_v3_fl(vec, 1.0f/num);
+ mul_v3_fl(vec, 1.0f / num);
}
-
+
/* reset */
density = vec[0] = vec[1] = vec[2] = 0.0f;
}
-
+
if (pd->flag & TEX_PD_TURBULENCE) {
-
+
if (pd->noise_influence == TEX_PD_NOISE_AGE) {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
+ pd->noise_depth, 0, pd->noise_basis);
}
else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
time = R.r.cfra / (float)R.r.efra;
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
+ pd->noise_depth, 0, pd->noise_basis);
//turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
}
else {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
+ pd->noise_depth, 0, pd->noise_basis);
}
turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
-
+
/* now we have an offset coordinate to use for the density lookup */
co[0] = texvec[0] + noise_fac * turb;
co[1] = texvec[1] + noise_fac * turb;
@@ -485,17 +521,17 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
if (num > 0) {
age /= num;
- mul_v3_fl(vec, 1.0f/num);
+ mul_v3_fl(vec, 1.0f / num);
}
-
+
texres->tin = density;
BRICONT;
-
+
if (pd->color_source == TEX_PD_COLOR_CONSTANT)
return retval;
-
+
retval |= TEX_RGB;
-
+
switch (pd->color_source) {
case TEX_PD_COLOR_PARTAGE:
if (pd->coba) {
@@ -510,7 +546,7 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
case TEX_PD_COLOR_PARTSPEED:
{
float speed = len_v3(vec) * pd->speed_scale;
-
+
if (pd->coba) {
if (do_colorband(pd->coba, speed, col)) {
texres->talpha = true;
@@ -533,9 +569,9 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
break;
}
BRICONTRGB;
-
+
return retval;
-
+
#if 0
if (texres->nor!=NULL) {
texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 065cdeab61c..2b1d5b8c1e5 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -306,22 +306,23 @@ static void makeraytree_single(Render *re)
RayObject *raytree;
RayFace *face = NULL;
VlakPrimitive *vlakprimitive = NULL;
- int faces = 0, obs = 0, special = 0;
+ int faces = 0, special = 0;
- for (obi=re->instancetable.first; obi; obi=obi->next)
- if (is_raytraceable(re, obi)) {
- ObjectRen *obr = obi->obr;
- obs++;
-
- if (has_special_rayobject(re, obi)) {
- special++;
- }
- else {
- int v;
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr))
- faces++;
+ for (obi = re->instancetable.first; obi; obi = obi->next) {
+ if (is_raytraceable(re, obi)) {
+ ObjectRen *obr = obi->obr;
+
+ if (has_special_rayobject(re, obi)) {
+ special++;
+ }
+ else {
+ int v;
+ for (v = 0;v < obr->totvlak; v++) {
+ VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ faces++;
+ }
+ }
}
}
}
@@ -794,7 +795,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con
traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
f= shr.alpha; f1= 1.0f-f;
- nf= d * shi.mat->filter;
+ nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f;
fr= 1.0f+ nf*(shi.r-1.0f);
fg= 1.0f+ nf*(shi.g-1.0f);
fb= 1.0f+ nf*(shi.b-1.0f);
@@ -1628,9 +1629,9 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int
shade_ray(is, &shi, &shr);
if (shi.mat->material_type == MA_TYPE_SURFACE) {
- const float d= (traflag & RAY_TRA) ?
- shade_by_transmission(is, &shi, &shr) :
- 1.0f;
+ const float d = (shi.mat->mode & MA_RAYTRANSP) ?
+ ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) :
+ 0.0f;
/* mix colors based on shadfac (rgb + amount of light factor) */
addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 6486844bacf..19beec9a6fe 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -48,9 +48,8 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "BKE_scene.h"
-#endif
+#include "BKE_camera.h"
+#include "BKE_scene.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -63,14 +62,32 @@
/********************************** Free *************************************/
+static void render_result_views_free(RenderResult *res)
+{
+ while (res->views.first) {
+ RenderView *rv = res->views.first;
+ BLI_remlink(&res->views, rv);
+
+ if (rv->rect32)
+ MEM_freeN(rv->rect32);
+
+ if (rv->rectz)
+ MEM_freeN(rv->rectz);
+
+ if (rv->rectf)
+ MEM_freeN(rv->rectf);
+
+ MEM_freeN(rv);
+ }
+}
+
void render_result_free(RenderResult *res)
{
if (res == NULL) return;
while (res->layers.first) {
RenderLayer *rl = res->layers.first;
-
- if (rl->rectf) MEM_freeN(rl->rectf);
+
/* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */
if (rl->acolrect) MEM_freeN(rl->acolrect);
if (rl->scolrect) MEM_freeN(rl->scolrect);
@@ -85,7 +102,9 @@ void render_result_free(RenderResult *res)
BLI_remlink(&res->layers, rl);
MEM_freeN(rl);
}
-
+
+ render_result_views_free(res);
+
if (res->rect32)
MEM_freeN(res->rect32);
if (res->rectz)
@@ -96,7 +115,9 @@ void render_result_free(RenderResult *res)
MEM_freeN(res->text);
if (res->error)
MEM_freeN(res->error);
-
+ if (res->stamp_data)
+ MEM_freeN(res->stamp_data);
+
MEM_freeN(res);
}
@@ -115,13 +136,44 @@ void render_result_free_list(ListBase *lb, RenderResult *rr)
}
}
-/********************************* Names *************************************/
+/********************************* multiview *************************************/
-/* NOTE: OpenEXR only supports 32 chars for layer+pass names
- * In blender we now use max 10 chars for pass, max 20 for layer */
-static const char *get_pass_name(int passtype, int channel)
+/* create a new views Listbase in rr without duplicating the memory pointers */
+void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
+{
+ RenderView *rview;
+
+ if (dst == NULL || src == NULL)
+ return;
+
+ for (rview = src->views.first; rview; rview = rview->next) {
+ RenderView *rv;
+
+ rv = MEM_mallocN(sizeof(RenderView), "new render view");
+ BLI_addtail(&dst->views, rv);
+
+ BLI_strncpy(rv->name, rview->name, sizeof(rv->name));
+ rv->rectf = rview->rectf;
+ rv->rectz = rview->rectz;
+ rv->rect32 = rview->rect32;
+ }
+}
+
+/* free the views created temporarily */
+void render_result_views_shallowdelete(RenderResult *rr)
+{
+ if (rr == NULL)
+ return;
+
+ while (rr->views.first) {
+ RenderView *rv = rr->views.first;
+ BLI_remlink(&rr->views, rv);
+ MEM_freeN(rv);
+ }
+}
+
+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";
@@ -308,122 +360,151 @@ static const char *get_pass_name(int passtype, int channel)
static int passtype_from_name(const char *str)
{
-
- if (STREQ(str, "Combined"))
+ if (STRPREFIX(str, "Combined"))
return SCE_PASS_COMBINED;
- if (STREQ(str, "Depth"))
+ if (STRPREFIX(str, "Depth"))
return SCE_PASS_Z;
- if (STREQ(str, "Vector"))
+ if (STRPREFIX(str, "Vector"))
return SCE_PASS_VECTOR;
- if (STREQ(str, "Normal"))
+ if (STRPREFIX(str, "Normal"))
return SCE_PASS_NORMAL;
- if (STREQ(str, "UV"))
+ if (STRPREFIX(str, "UV"))
return SCE_PASS_UV;
- if (STREQ(str, "Color"))
+ if (STRPREFIX(str, "Color"))
return SCE_PASS_RGBA;
- if (STREQ(str, "Emit"))
+ if (STRPREFIX(str, "Emit"))
return SCE_PASS_EMIT;
- if (STREQ(str, "Diffuse"))
+ if (STRPREFIX(str, "Diffuse"))
return SCE_PASS_DIFFUSE;
- if (STREQ(str, "Spec"))
+ if (STRPREFIX(str, "Spec"))
return SCE_PASS_SPEC;
- if (STREQ(str, "Shadow"))
+ if (STRPREFIX(str, "Shadow"))
return SCE_PASS_SHADOW;
- if (STREQ(str, "AO"))
+ if (STRPREFIX(str, "AO"))
return SCE_PASS_AO;
- if (STREQ(str, "Env"))
+ if (STRPREFIX(str, "Env"))
return SCE_PASS_ENVIRONMENT;
- if (STREQ(str, "Indirect"))
+ if (STRPREFIX(str, "Indirect"))
return SCE_PASS_INDIRECT;
- if (STREQ(str, "Reflect"))
+ if (STRPREFIX(str, "Reflect"))
return SCE_PASS_REFLECT;
- if (STREQ(str, "Refract"))
+ if (STRPREFIX(str, "Refract"))
return SCE_PASS_REFRACT;
- if (STREQ(str, "IndexOB"))
+ if (STRPREFIX(str, "IndexOB"))
return SCE_PASS_INDEXOB;
- if (STREQ(str, "IndexMA"))
+ if (STRPREFIX(str, "IndexMA"))
return SCE_PASS_INDEXMA;
- if (STREQ(str, "Mist"))
+ if (STRPREFIX(str, "Mist"))
return SCE_PASS_MIST;
- if (STREQ(str, "RayHits"))
+ if (STRPREFIX(str, "RayHits"))
return SCE_PASS_RAYHITS;
- if (STREQ(str, "DiffDir"))
+ if (STRPREFIX(str, "DiffDir"))
return SCE_PASS_DIFFUSE_DIRECT;
- if (STREQ(str, "DiffInd"))
+ if (STRPREFIX(str, "DiffInd"))
return SCE_PASS_DIFFUSE_INDIRECT;
- if (STREQ(str, "DiffCol"))
+ if (STRPREFIX(str, "DiffCol"))
return SCE_PASS_DIFFUSE_COLOR;
- if (STREQ(str, "GlossDir"))
+ if (STRPREFIX(str, "GlossDir"))
return SCE_PASS_GLOSSY_DIRECT;
- if (STREQ(str, "GlossInd"))
+ if (STRPREFIX(str, "GlossInd"))
return SCE_PASS_GLOSSY_INDIRECT;
- if (STREQ(str, "GlossCol"))
+ if (STRPREFIX(str, "GlossCol"))
return SCE_PASS_GLOSSY_COLOR;
- if (STREQ(str, "TransDir"))
+ if (STRPREFIX(str, "TransDir"))
return SCE_PASS_TRANSM_DIRECT;
- if (STREQ(str, "TransInd"))
+ if (STRPREFIX(str, "TransInd"))
return SCE_PASS_TRANSM_INDIRECT;
- if (STREQ(str, "TransCol"))
+ if (STRPREFIX(str, "TransCol"))
return SCE_PASS_TRANSM_COLOR;
- if (STREQ(str, "SubsurfaceDir"))
+ if (STRPREFIX(str, "SubsurfaceDir"))
return SCE_PASS_SUBSURFACE_DIRECT;
- if (STREQ(str, "SubsurfaceInd"))
+ if (STRPREFIX(str, "SubsurfaceInd"))
return SCE_PASS_SUBSURFACE_INDIRECT;
- if (STREQ(str, "SubsurfaceCol"))
+ if (STRPREFIX(str, "SubsurfaceCol"))
return SCE_PASS_SUBSURFACE_COLOR;
return 0;
}
+
+static void set_pass_name(char *passname, int passtype, int channel, const char *view)
+{
+ 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);
+ }
+ else {
+ BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view);
+ }
+}
+
/********************************** New **************************************/
-static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
+static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
{
- const char *typestr = get_pass_name(passtype, 0);
+ const size_t 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);
- int rectsize = rr->rectx * rr->recty * channels;
+ size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
BLI_addtail(&rl->passes, rpass);
rpass->passtype = passtype;
rpass->channels = channels;
rpass->rectx = rl->rectx;
rpass->recty = rl->recty;
- BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
+ 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->view, viewname, sizeof(rpass->view));
if (rl->exrhandle) {
int a;
for (a = 0; a < channels; a++)
- IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
+ IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false);
}
else {
float *rect;
@@ -452,6 +533,10 @@ static const char *debug_pass_type_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";
}
@@ -460,13 +545,15 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
RenderLayer *rl,
int channels,
int pass_type,
- int debug_type)
+ int debug_type,
+ const char *view)
{
- RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type);
+ RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
rpass->debug_type = debug_type;
BLI_strncpy(rpass->name,
debug_pass_type_name_get(debug_type),
sizeof(rpass->name));
+ BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name));
return rpass;
}
#endif
@@ -475,12 +562,14 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
/* will read info from Render *re to define layers */
/* called in threads */
/* re->winx,winy is coordinate space of entire image, partrct the part within */
-RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername)
+RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname)
{
RenderResult *rr;
RenderLayer *rl;
+ RenderView *rv;
SceneRenderLayer *srl;
- int rectx, recty, nr;
+ int rectx, recty;
+ int nr;
rectx = BLI_rcti_size_x(partrct);
recty = BLI_rcti_size_y(partrct);
@@ -505,6 +594,8 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rr->do_exr_tile = true;
}
+ render_result_views_new(rr, &re->r);
+
/* check renderdata for amount of layers */
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
@@ -538,84 +629,90 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (rr->do_exr_tile) {
rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
-
rl->exrhandle = IMB_exr_get_handle();
-
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
}
- else
- rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
-
- if (srl->passflag & SCE_PASS_Z)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
- if (srl->passflag & SCE_PASS_VECTOR)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
- if (srl->passflag & SCE_PASS_NORMAL)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
- if (srl->passflag & SCE_PASS_UV)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_UV);
- if (srl->passflag & SCE_PASS_RGBA)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
- if (srl->passflag & SCE_PASS_EMIT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT);
- if (srl->passflag & SCE_PASS_DIFFUSE)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
- if (srl->passflag & SCE_PASS_SPEC)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
- if (srl->passflag & SCE_PASS_AO)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
- if (srl->passflag & SCE_PASS_ENVIRONMENT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT);
- if (srl->passflag & SCE_PASS_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT);
- if (srl->passflag & SCE_PASS_SHADOW)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
- if (srl->passflag & SCE_PASS_REFLECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
- if (srl->passflag & SCE_PASS_REFRACT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
- if (srl->passflag & SCE_PASS_INDEXOB)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
- if (srl->passflag & SCE_PASS_INDEXMA)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA);
- if (srl->passflag & SCE_PASS_MIST)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST);
- if (rl->passflag & SCE_PASS_RAYHITS)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS);
- if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT);
- if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT);
- if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR);
- if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT);
- if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT);
- if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR);
- if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT);
- if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT);
- if (srl->passflag & SCE_PASS_TRANSM_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR);
- if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT);
- if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT);
- if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR);
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0])
+ if (!STREQ(view, viewname))
+ continue;
+
+ if (rr->do_exr_tile)
+ 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);
+
+ if (srl->passflag & SCE_PASS_Z)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_Z, view);
+ if (srl->passflag & SCE_PASS_VECTOR)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR, view);
+ if (srl->passflag & SCE_PASS_NORMAL)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL, view);
+ if (srl->passflag & SCE_PASS_UV)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_UV, view);
+ if (srl->passflag & SCE_PASS_RGBA)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA, view);
+ if (srl->passflag & SCE_PASS_EMIT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE, view);
+ if (srl->passflag & SCE_PASS_SPEC)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC, view);
+ if (srl->passflag & SCE_PASS_AO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_AO, view);
+ if (srl->passflag & SCE_PASS_ENVIRONMENT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
+ if (srl->passflag & SCE_PASS_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_SHADOW)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW, view);
+ if (srl->passflag & SCE_PASS_REFLECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT, view);
+ if (srl->passflag & SCE_PASS_REFRACT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT, view);
+ if (srl->passflag & SCE_PASS_INDEXOB)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB, view);
+ if (srl->passflag & SCE_PASS_INDEXMA)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA, view);
+ if (srl->passflag & SCE_PASS_MIST)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST, view);
+ if (rl->passflag & SCE_PASS_RAYHITS)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
+ if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
+ if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_TRANSM_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
#ifdef WITH_CYCLES_DEBUG
- if (BKE_scene_use_new_shading_nodes(re->scene)) {
- render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG,
- RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS);
- }
+ if (BKE_scene_use_new_shading_nodes(re->scene)) {
+ render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG,
+ re->r.debug_pass_type, view);
+ }
#endif
+ }
}
/* sss, previewrender and envmap don't do layers, so we make a default one */
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
@@ -628,18 +725,23 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
/* duplicate code... */
if (rr->do_exr_tile) {
rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
-
rl->exrhandle = IMB_exr_get_handle();
-
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
}
- else {
- rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0])
+ if (strcmp(view, viewname) != 0)
+ continue;
+
+ if (rr->do_exr_tile)
+ 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);
}
-
+
/* note, this has to be in sync with scene.c */
rl->lay = (1 << 20) - 1;
rl->layflag = 0x7FFF; /* solid ztra halo strand */
@@ -657,15 +759,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
}
/* allocate osa new results for samples */
-RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers)
+RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
{
int a;
if (re->osa == 0)
- return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
+ return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
for (a = 0; a < re->osa; a++) {
- RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
+ RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
BLI_addtail(lb, rr);
rr->sample_nr = a;
}
@@ -686,28 +788,98 @@ static void *ml_addlayer_cb(void *base, const char *str)
return rl;
}
-static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float *rect, int totchan, const char *chan_id)
+static void ml_addpass_cb(void *base, void *lay, const char *str, 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);
if (rpass->passtype == 0) printf("unknown pass %s\n", str);
rl->passflag |= rpass->passtype;
- BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME);
/* channel id chars */
for (a = 0; a < totchan; a++)
rpass->chan_id[a] = chan_id[a];
-
+
rpass->rect = rect;
+ 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)
+{
+ RenderResult *rr = base;
+ RenderView *rv;
+
+ rv = MEM_callocN(sizeof(RenderView), "new render view");
+ BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME);
+
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+
+ if (STREQ(str, STEREO_LEFT_NAME)) {
+ BLI_addhead(&rr->views, rv);
+ }
+ else if (STREQ(str, STEREO_RIGHT_NAME)) {
+ RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name));
+
+ if (left_rv == NULL) {
+ BLI_addhead(&rr->views, rv);
+ }
+ else {
+ BLI_insertlinkafter(&rr->views, left_rv, rv);
+ }
+ }
+ else {
+ BLI_addtail(&rr->views, rv);
+ }
+
+ return rv;
+}
+
+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;
+
+ if (rpa->passtype > rpb->passtype)
+ return 1;
+ else if (rpa->passtype < rpb->passtype)
+ return 0;
+
+ /* they have the same type */
+ /* left first */
+ if (STREQ(rpa->view, STEREO_LEFT_NAME))
+ return 0;
+ else if (STREQ(rpb->view, STEREO_LEFT_NAME))
+ return 1;
+
+ /* right second */
+ if (STREQ(rpa->view, STEREO_RIGHT_NAME))
+ return 0;
+ else if (STREQ(rpb->view, STEREO_RIGHT_NAME))
+ return 1;
+
+ /* remaining in ascending id order */
+ return (rpa->view_id < rpb->view_id);
}
-/* from imbuf, if a handle was returned we convert this to render result */
+/* from imbuf, if a handle was returned and it's not a singlelayer multiview we convert this to render result */
RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
@@ -718,13 +890,17 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
rr->rectx = rectx;
rr->recty = recty;
- IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb);
+ IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb);
for (rl = rr->layers.first; rl; rl = rl->next) {
+ int c=0;
rl->rectx = rectx;
rl->recty = recty;
+ BLI_listbase_sort(&rl->passes, order_render_passes);
+
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ printf("%d: %s\n", c++, rpass->name);
rpass->rectx = rectx;
rpass->recty = recty;
@@ -738,26 +914,56 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
return rr;
}
+void render_result_view_new(RenderResult *rr, const char *viewname)
+{
+ RenderView *rv = MEM_callocN(sizeof(RenderView), "new render view");
+ BLI_addtail(&rr->views, rv);
+ BLI_strncpy(rv->name, viewname, sizeof(rv->name));
+}
+
+void render_result_views_new(RenderResult *rr, RenderData *rd)
+{
+ SceneRenderView *srv;
+
+ /* clear previously existing views - for sequencer */
+ render_result_views_free(rr);
+
+ /* check renderdata for amount of views */
+ if ((rd->scemode & R_MULTIVIEW)) {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ render_result_view_new(rr, srv->name);
+ }
+ }
+
+ /* we always need at least one view */
+ if (BLI_listbase_count_ex(&rr->views, 1) == 0) {
+ render_result_view_new(rr, "");
+ }
+}
+
/*********************************** Merge ***********************************/
static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
{
- int y, ofs, copylen, tilex, tiley;
+ int y, tilex, tiley;
+ size_t ofs, copylen;
copylen = tilex = rrpart->rectx;
tiley = rrpart->recty;
if (rrpart->crop) { /* filters add pixel extra */
- tile += pixsize * (rrpart->crop + rrpart->crop * tilex);
+ tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex);
copylen = tilex - 2 * rrpart->crop;
tiley -= 2 * rrpart->crop;
- ofs = (rrpart->tilerect.ymin + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
+ ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
target += pixsize * ofs;
}
else {
- ofs = (rrpart->tilerect.ymin * rr->rectx + rrpart->tilerect.xmin);
+ ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
target += pixsize * ofs;
}
@@ -783,16 +989,19 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
for (rl = rr->layers.first; rl; rl = rl->next) {
rlp = RE_GetRenderLayer(rrpart, rl->name);
if (rlp) {
- /* combined */
- if (rl->rectf && rlp->rectf)
- do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
-
/* passes are allocated in sync */
for (rpass = rl->passes.first, rpassp = rlp->passes.first;
rpass && rpassp;
- rpass = rpass->next, rpassp = rpassp->next)
+ rpass = rpass->next)
{
+ /* renderresult have all passes, renderpart only the active view's passes */
+ if (strcmp(rpassp->name, rpass->name) != 0)
+ continue;
+
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
+
+ /* manually get next render pass */
+ rpassp = rpassp->next;
}
}
}
@@ -801,7 +1010,7 @@ 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[16];
+ static char name[EXR_PASS_MAXNAME];
int len;
BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
@@ -813,55 +1022,111 @@ static char *make_pass_name(RenderPass *rpass, int chan)
return name;
}
-/* filename already made absolute */
-/* called from within UI, saves both rendered result as a file-read result */
-bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress)
+/* 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
+ * else saves stereo3d
+ */
+bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view)
{
RenderLayer *rl;
RenderPass *rpass;
+ RenderView *rview;
void *exrhandle = IMB_exr_get_handle();
bool success;
-
- BLI_make_existing_file(filename);
-
- /* composite result */
- if (rr->rectf) {
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4 * rr->rectx, rr->rectf);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4 * rr->rectx, rr->rectf + 1);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4 * rr->rectx, rr->rectf + 2);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4 * rr->rectx, rr->rectf + 3);
+ int a, nr;
+ const char *chan_view = NULL;
+ int compress = (imf ? imf->exr_codec : 0);
+ size_t width, height;
+
+ const bool is_mono = view && !multiview;
+ const bool use_half_float = (imf->depth == R_IMF_CHAN_DEPTH_16);
+
+ width = rr->rectx;
+ height = rr->recty;
+
+ if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) {
+ /* single layer OpenEXR */
+ const char *RGBAZ[] = {"R", "G", "B", "A", "Z"};
+ for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
+ IMB_exr_add_view(exrhandle, rview->name);
+
+ if (rview->rectf) {
+ for (a = 0; a < 4; a++) {
+ IMB_exr_add_channel(exrhandle, "", RGBAZ[a],
+ rview->name, 4, 4 * width, rview->rectf + a,
+ use_half_float);
+ }
+ if (rview->rectz) {
+ /* Z pass is always stored as float. */
+ IMB_exr_add_channel(exrhandle, "", RGBAZ[4],
+ rview->name, 1, width, rview->rectz,
+ false);
+ }
+ }
+ }
}
-
- /* add layers/passes and assign channels */
- for (rl = rr->layers.first; rl; rl = rl->next) {
-
- /* combined */
- if (rl->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++) {
- IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rr->rectx, rl->rectf + a);
+ else {
+ for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
+ if (is_mono) {
+ if (!STREQ(view, rview->name)) {
+ continue;
+ }
+ chan_view = "";
+ }
+ else {
+ /* if rendered only one view, we treat as a a non-view render */
+ chan_view = rview->name;
+ }
+
+ IMB_exr_add_view(exrhandle, rview->name);
+
+ if (rview->rectf) {
+ for (a = 0; a < 4; a++) {
+ IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a),
+ chan_view, 4, 4 * width, rview->rectf + a,
+ use_half_float);
+ }
}
}
-
- /* passes are allocated in sync */
- for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
- int a, xstride = rpass->channels;
- for (a = 0; a < xstride; a++) {
- if (rpass->passtype) {
- IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
- xstride, xstride * rr->rectx, rpass->rect + a);
+
+ /* add layers/passes and assign channels */
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+
+ /* passes are allocated in sync */
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ const int xstride = rpass->channels;
+
+ if (is_mono) {
+ if (!STREQ(view, rpass->view)) {
+ continue;
+ }
+ chan_view = "";
}
else {
- IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a),
- xstride, xstride * rr->rectx, rpass->rect + a);
+ /* if rendered only one view, we treat as a a non-view render */
+ chan_view = (nr > 1 ? rpass->view :"");
+ }
+
+ 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);
+ }
}
}
}
}
- /* when the filename has no permissions, this can fail */
- if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) {
+ BLI_make_existing_file(filename);
+
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) {
IMB_exr_write_channels(exrhandle);
success = true;
}
@@ -870,8 +1135,8 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
BKE_report(reports, RPT_ERROR, "Error writing render result (see console)");
success = false;
}
- IMB_exr_close(exrhandle);
+ IMB_exr_close(exrhandle);
return success;
}
@@ -932,7 +1197,7 @@ void render_result_single_layer_end(Render *re)
/************************* EXR Tile File Rendering ***************************/
-static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
+static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname)
{
RenderLayer *rlp, *rl;
RenderPass *rpassp;
@@ -955,21 +1220,17 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
else {
offs = 0;
}
-
- /* combined */
- if (rlp->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++) {
- IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs);
- }
- }
-
+
/* passes are allocated in sync */
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
- int a, xstride = rpassp->channels;
+ const int xstride = rpassp->channels;
+ int a;
+ char passname[EXR_PASS_MAXNAME];
+
for (a = 0; a < xstride; a++) {
- IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
+ set_pass_name(passname, rpassp->passtype, a, rpassp->view);
+
+ IMB_exr_set_channel(rl->exrhandle, rlp->name, passname,
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
}
}
@@ -988,13 +1249,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
continue;
}
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname);
}
BLI_unlock_thread(LOCK_IMAGE);
}
-static void save_empty_result_tiles(Render *re)
+void render_result_save_empty_result_tiles(Render *re)
{
RenderPart *pa;
RenderResult *rr;
@@ -1002,13 +1263,13 @@ static void save_empty_result_tiles(Render *re)
for (rr = re->result; rr; rr = rr->next) {
for (rl = rr->layers.first; rl; rl = rl->next) {
- IMB_exrtile_clear_channels(rl->exrhandle);
+ IMB_exr_clear_channels(rl->exrhandle);
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status != PART_STATUS_READY) {
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname);
}
}
}
@@ -1037,8 +1298,6 @@ void render_result_exr_file_end(Render *re)
RenderResult *rr;
RenderLayer *rl;
- save_empty_result_tiles(re);
-
for (rr = re->result; rr; rr = rr->next) {
for (rl = rr->layers.first; rl; rl = rl->next) {
IMB_exr_close(rl->exrhandle);
@@ -1055,10 +1314,10 @@ void render_result_exr_file_end(Render *re)
}
/* save part into exr file */
-void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart)
+void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const char *viewname)
{
for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next)
- save_render_result_tile(rr, rrpart);
+ save_render_result_tile(rr, rrpart, viewname);
}
/* path to temporary exr file */
@@ -1088,7 +1347,7 @@ int render_result_exr_file_read_sample(Render *re, int sample)
bool success = true;
RE_FreeRenderResult(re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
for (rl = re->result->layers.first; rl; rl = rl->next) {
render_result_exr_file_path(re->scene, rl->name, sample, str);
@@ -1129,23 +1388,20 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
for (rl = rr->layers.first; rl; rl = rl->next) {
if (rl_single && rl_single != rl)
continue;
-
- /* combined */
- if (rl->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++)
- IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rectx, rl->rectf + a);
- }
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
- int a, xstride = rpass->channels;
- for (a = 0; a < xstride; a++)
- IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
+ const int xstride = rpass->channels;
+ int a;
+ char passname[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,
xstride, xstride * rectx, rpass->rect + a);
+ }
- BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
+ set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
}
}
@@ -1191,7 +1447,8 @@ void render_result_exr_file_cache_write(Render *re)
render_result_exr_file_cache_path(re->scene, root, str);
printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
- RE_WriteRenderResult(NULL, rr, str, 0);
+
+ RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL);
}
/* For cache, makes exact copy of render result */
@@ -1201,7 +1458,7 @@ bool render_result_exr_file_cache_read(Render *re)
char *root = U.render_cachedir;
RE_FreeRenderResult(re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
/* First try cache. */
render_result_exr_file_cache_path(re->scene, root, str);
@@ -1216,15 +1473,16 @@ bool render_result_exr_file_cache_read(Render *re)
/*************************** Combined Pixel Rect *****************************/
-ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
+ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id)
{
ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
-
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
/* if not exists, BKE_imbuf_write makes one */
- ibuf->rect = (unsigned int *)rr->rect32;
- ibuf->rect_float = rr->rectf;
- ibuf->zbuf_float = rr->rectz;
-
+ ibuf->rect = (unsigned int *) rv->rect32;
+ ibuf->rect_float = rv->rectf;
+ ibuf->zbuf_float = rv->rectz;
+
/* float factor for random dither, imbuf takes care of it */
ibuf->dither = rd->dither_intensity;
@@ -1259,57 +1517,97 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
return ibuf;
}
-void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf)
+void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id)
{
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
if (ibuf->rect_float) {
- if (!rr->rectf)
- rr->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
+ if (!rv->rectf)
+ rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
- memcpy(rr->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
+ memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
/* TSK! Since sequence render doesn't free the *rr render result, the old rect32
* can hang around when sequence render has rendered a 32 bits one before */
- if (rr->rect32) {
- MEM_freeN(rr->rect32);
- rr->rect32 = NULL;
- }
+ MEM_SAFE_FREE(rv->rect32);
}
else if (ibuf->rect) {
- if (!rr->rect32)
- rr->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
+ if (!rv->rect32)
+ rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
- memcpy(rr->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
+ memcpy(rv->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
/* Same things as above, old rectf can hang around from previous render. */
- if (rr->rectf) {
- MEM_freeN(rr->rectf);
- rr->rectf = NULL;
- }
+ MEM_SAFE_FREE(rv->rectf);
}
}
-void render_result_rect_fill_zero(RenderResult *rr)
+void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
{
- if (rr->rectf)
- memset(rr->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
- else if (rr->rect32)
- memset(rr->rect32, 0, 4 * rr->rectx * rr->recty);
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
+ if (rv->rectf)
+ memset(rv->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
+ else if (rv->rect32)
+ memset(rv->rect32, 0, 4 * rr->rectx * rr->recty);
else
- rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
+ rv->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
}
void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty,
- const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
+ const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings,
+ const int view_id)
{
- if (rr->rect32) {
- memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty);
- }
- else if (rr->rectf) {
- IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4,
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
+ if (rv->rect32)
+ memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty);
+ else if (rv->rectf)
+ IMB_display_buffer_transform_apply((unsigned char *) rect, rv->rectf, rr->rectx, rr->recty, 4,
view_settings, display_settings, true);
- }
else
/* else fill with black */
memset(rect, 0, sizeof(int) * rectx * recty);
}
+
+/*************************** multiview functions *****************************/
+
+bool RE_HasFakeLayer(RenderResult *res)
+{
+ RenderView *rv;
+
+ if (res == NULL)
+ return false;
+
+ rv = res->views.first;
+ if (rv == NULL)
+ return false;
+
+ return (rv->rect32 || rv->rectf);
+}
+
+bool RE_RenderResult_is_stereo(RenderResult *res)
+{
+ if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name)))
+ return false;
+
+ if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)))
+ return false;
+
+ return true;
+}
+
+RenderView *RE_RenderViewGetById(RenderResult *res, const int view_id)
+{
+ RenderView *rv = BLI_findlink(&res->views, view_id);
+ BLI_assert(res->views.first);
+ return rv ? rv : res->views.first;
+}
+
+RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname)
+{
+ RenderView *rv = BLI_findstring(&res->views, viewname, offsetof(RenderView, name));
+ BLI_assert(res->views.first);
+ return rv ? rv : res->views.first;
+}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 17039bca63a..6acdde6af9c 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -116,7 +116,7 @@ static void init_render_texture(Render *re, Tex *tex)
if (G.is_rendering && re) {
if (re->r.mode & R_ENVMAP)
if (tex->env->stype==ENV_ANIM)
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
}
}
}
@@ -1348,7 +1348,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
/* fact = texture strength, facg = button strength value */
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
- float facm, col;
+ float facm;
switch (blendtype) {
case MTEX_BLEND:
@@ -1435,13 +1435,10 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_LIGHT:
fact*= facg;
-
- col= fact*tex[0];
- if (col > out[0]) in[0]= col; else in[0]= out[0];
- col= fact*tex[1];
- if (col > out[1]) in[1]= col; else in[1]= out[1];
- col= fact*tex[2];
- if (col > out[2]) in[2]= col; else in[2]= out[2];
+
+ in[0] = max_ff(fact * tex[0], out[0]);
+ in[1] = max_ff(fact * tex[1], out[1]);
+ in[2] = max_ff(fact * tex[2], out[2]);
break;
case MTEX_BLEND_HUE:
@@ -1982,14 +1979,14 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
/* use texres for the center sample, set rgbnor */
rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image);
- Hll = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin;
+ Hll = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin;
/* use ttexr for the other 2 taps */
multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hlr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hlr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image);
- Hul = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hul = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hlr - Hll);
dHdy = Hscale*(Hul - Hll);
@@ -2020,17 +2017,17 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
/* use texres for the center sample, set rgbnor */
rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image);
- /* Hc = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; */ /* UNUSED */
+ /* Hc = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; */ /* UNUSED */
/* use ttexr for the other taps */
multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image);
- Hl = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hl = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image);
- Hd = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hd = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image);
- Hu = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hu = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hr - Hl);
dHdy = Hscale*(Hu - Hd);
@@ -2328,7 +2325,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -2434,7 +2431,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
BKE_image_pool_release_ibuf(ima, ibuf, re->pool);
}
-
+
if (mtex->mapto & MAP_COL) {
float colfac= mtex->colfac*stencilTin;
texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
@@ -2568,7 +2565,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
}
if (rgbnor & TEX_RGB) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
@@ -2596,7 +2593,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
if (rgbnor & TEX_RGB) {
if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = rgb_to_grayscale(&texres.tr);
+ else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
if (mtex->mapto & MAP_REF) {
@@ -2767,7 +2764,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -2836,7 +2833,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
/* convert RGB to intensity if intensity info isn't provided */
if (rgbnor & TEX_RGB) {
if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = rgb_to_grayscale(&texres.tr);
+ else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
if ((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) {
@@ -2934,7 +2931,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3006,7 +3003,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
texres.tin = texres.ta;
}
else {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
}
@@ -3140,7 +3137,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3215,7 +3212,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
}
}
if (mtex->mapto & WOMAP_BLEND) {
- if (rgb) texres.tin = rgb_to_bw(&texres.tr);
+ if (rgb) texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
*blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->blendfac, mtex->blendtype);
}
@@ -3356,7 +3353,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3455,7 +3452,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg,
rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool, skip_load_image);
if (rgb) {
- texr.tin = rgb_to_bw(&texr.tr);
+ texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
}
else {
texr.tr= mtex->r;
@@ -3493,7 +3490,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
if (firsttime) {
for (a=0; a<BLENDER_MAX_THREADS; a++) {
memset(&imatex[a], 0, sizeof(Tex));
- default_tex(&imatex[a]);
+ BKE_texture_default(&imatex[a]);
imatex[a].type= TEX_IMAGE;
}
@@ -3614,7 +3611,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
}
/* copy texture */
- tex= mtex->tex = localize_texture(cur_tex);
+ tex= mtex->tex = BKE_texture_localize(cur_tex);
/* update texture anims */
BKE_animsys_evaluate_animdata(scene, &tex->id, tex->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
@@ -3631,7 +3628,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
unit_m4(dummy_re.viewmat);
unit_m4(dummy_re.winmat);
dummy_re.winx = dummy_re.winy = 128;
- cache_pointdensity(&dummy_re, tex);
+ cache_pointdensity(&dummy_re, tex->pd);
}
/* update image sequences and movies */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 5b054005bac..a634bd9780c 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -181,8 +181,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
if (fullsample) {
for (sample=0; sample<totsample; sample++)
- if (ps->mask & (1 << sample))
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ if (ps->mask & (1 << sample)) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
else {
fac= ((float)amountm)/(float)R.osa;
@@ -214,8 +216,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
if (fullsample) {
for (sample=0; sample<totsample; sample++)
- if (!(mask & (1 << sample)))
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ if (!(mask & (1 << sample))) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
else {
col[0]= accol[0];
@@ -223,8 +227,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
col[2]= accol[2];
col[3]= accol[3];
- for (sample=0; sample<totsample; sample++)
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ for (sample=0; sample<totsample; sample++) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
}
@@ -305,8 +311,10 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl)
zz= calchalo_z(har, *rz);
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++)
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ for (sample=0; sample<totsample; sample++) {
+ float * rect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(rect + od*4, col, har->add);
+ }
}
}
}
@@ -359,7 +367,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- pass= rlpp[sample]->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -370,7 +379,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)count)/(float)R.osa;
- pass= rl->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
pass[2]+= fac*col[2];
@@ -390,7 +400,9 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- pass= rlpp[sample]->rectf + od*4;
+
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -401,7 +413,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass= rl->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
pass[2]+= fac*col[2];
@@ -420,7 +433,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
renderspothalo(&shi, col, 1.0f);
for (sample=0; sample<totsample; sample++) {
- pass= rlpp[sample]->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -444,14 +458,14 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
{
RenderPass *rpass;
- /* combined rgb */
- add_filt_fmask(curmask, shr->combined, rl->rectf + 4*offset, rectx);
-
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
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;
@@ -555,15 +569,16 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
{
RenderPass *rpass;
float *fp;
-
- fp= rl->rectf + 4*offset;
- copy_v4_v4(fp, shr->combined);
-
+
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
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;
@@ -681,7 +696,8 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl)
bool done = false;
for (sample= 0; sample<totsample; sample++) {
- float *pass= rlpp[sample]->rectf + od;
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od;
if (pass[3]<1.0f) {
@@ -742,8 +758,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) + od;
- float *rgbrect = rlpp[sample]->rectf + 4*od;
+ 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;
float rgb[3] = {0};
bool done = false;
@@ -978,8 +994,8 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
return;
for (sample= 0; sample<totsample; sample++) {
- float *rectf= rlpp[sample]->rectf;
-
+ float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+
for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
rectf[0] = MAX2(rectf[0], 0.0f);
rectf[1] = MAX2(rectf[1], 0.0f);
@@ -1060,7 +1076,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);
+ fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname);
if (fp==NULL) break;
for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
@@ -1171,6 +1187,8 @@ 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);
+
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1211,7 +1229,7 @@ void zbufshadeDA_tile(RenderPart *pa)
if (R.flag & R_ZTRA || R.totstrand) {
if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
if (pa->fullresult.first) {
- zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist);
+ zbuffer_transp_shade(pa, rl, rect, &psmlist);
}
else {
unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
@@ -1220,9 +1238,9 @@ void zbufshadeDA_tile(RenderPart *pa)
rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
/* swap for live updates, and it is used in zbuf.c!!! */
- SWAP(float *, rl->acolrect, rl->rectf);
- ztramask= zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist);
- SWAP(float *, rl->acolrect, rl->rectf);
+ SWAP(float *, rl->acolrect, rect);
+ ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist);
+ SWAP(float *, rl->acolrect, rect);
/* zbuffer transp only returns ztramask if there's solid rendered */
if (ztramask)
@@ -1231,7 +1249,8 @@ void zbufshadeDA_tile(RenderPart *pa)
if (ztramask && solidmask) {
unsigned short *sps= solidmask, *spz= ztramask;
unsigned short fullmask= (1<<R.osa)-1;
- float *fcol= rl->rectf; float *acol= rl->acolrect;
+ float *fcol= rect;
+ float *acol= rl->acolrect;
int x;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
@@ -1242,7 +1261,8 @@ void zbufshadeDA_tile(RenderPart *pa)
}
}
else {
- float *fcol= rl->rectf; float *acol= rl->acolrect;
+ float *fcol= rect;
+ float *acol= rl->acolrect;
int x;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
addAlphaOverFloat(fcol, acol);
@@ -1265,7 +1285,7 @@ void zbufshadeDA_tile(RenderPart *pa)
/* extra layers */
if (rl->layflag & SCE_LAY_EDGE)
if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rl->rectf, edgerect);
+ edge_enhance_add(pa, rect, edgerect);
if (rl->passflag & SCE_PASS_VECTOR)
reset_sky_speed(pa, rl);
@@ -1319,6 +1339,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);
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1342,7 +1363,7 @@ void zbufshade_tile(RenderPart *pa)
rr->renlay= rl;
if (rl->layflag & SCE_LAY_SOLID) {
- const float *fcol= rl->rectf;
+ const float *fcol = rect;
const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz;
int x, y, offs=0, seed;
@@ -1405,11 +1426,11 @@ void zbufshade_tile(RenderPart *pa)
rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
/* swap for live updates */
- SWAP(float *, rl->acolrect, rl->rectf);
- zbuffer_transp_shade(pa, rl, rl->rectf, NULL);
- SWAP(float *, rl->acolrect, rl->rectf);
+ SWAP(float *, rl->acolrect, rect);
+ zbuffer_transp_shade(pa, rl, rect, NULL);
+ SWAP(float *, rl->acolrect, rect);
- fcol= rl->rectf; acol= rl->acolrect;
+ fcol= rect; acol= rl->acolrect;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
addAlphaOverFloat(fcol, acol);
}
@@ -1427,7 +1448,7 @@ void zbufshade_tile(RenderPart *pa)
if (!R.test_break(R.tbh)) {
if (rl->layflag & SCE_LAY_EDGE)
if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rl->rectf, edgerect);
+ edge_enhance_add(pa, rect, edgerect);
}
if (rl->passflag & SCE_PASS_VECTOR)
@@ -1654,7 +1675,7 @@ void zbufshade_sss_tile(RenderPart *pa)
return;
}
- fcol= rl->rectf;
+ fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
@@ -1938,6 +1959,7 @@ void add_halo_flare(Render *re)
RenderLayer *rl;
HaloRen *har;
int a, mode;
+ float *rect;
/* for now, we get the first renderlayer in list with halos set */
for (rl= rr->layers.first; rl; rl= rl->next) {
@@ -1945,8 +1967,11 @@ void add_halo_flare(Render *re)
if ((rl->layflag & SCE_LAY_HALO) == 0)
continue;
- if (rl->rectf==NULL)
- continue;
+
+ rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+
+ if (rl==NULL || rect)
+ return;
mode= R.r.mode;
R.r.mode &= ~R_PANORAMA;
@@ -1958,7 +1983,7 @@ void add_halo_flare(Render *re)
if (har->flarec && (har->lay & rl->lay)) {
do_draw = true;
- renderflare(rr, rl->rectf, har);
+ renderflare(rr, rect, har);
}
}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 01055d87a38..5a5e67e1e43 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -423,14 +423,11 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
+ mul_v3_m4v3(shi->gl, R.viewinv, shi->co);
if (shi->osatex) {
- copy_v3_v3(shi->dxgl, shi->dxco);
- mul_mat3_m4_v3(R.viewinv, shi->dxgl);
- copy_v3_v3(shi->dygl, shi->dyco);
- mul_mat3_m4_v3(R.viewinv, shi->dygl);
+ mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco);
+ mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco);
}
}
@@ -633,7 +630,7 @@ void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float v
dyco[2] = 0.0f;
if (dxyview) {
- if (co[2] != 0.0f) fac = 1.0f / co[2]; else fac = 0.0f;
+ fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f;
dxyview[0] = -R.viewdx * fac;
dxyview[1] = -R.viewdy * fac;
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 63a97a04b39..39dfa48d3f1 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -55,6 +55,8 @@
#include "shading.h" /* own include */
+#include "IMB_colormanagement.h"
+
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wdouble-promotion"
@@ -948,7 +950,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi)
if (ma->ramp_col) {
if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- float fac = rgb_to_grayscale(diff);
+ float fac = IMB_colormanagement_get_luminance(diff);
do_colorband(ma->ramp_col, fac, col);
/* blending method */
@@ -960,7 +962,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi)
}
/* r,g,b denote energy, ramp is used with different values to make new material color */
-static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b)
+static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3])
{
Material *ma= shi->mat;
@@ -969,9 +971,9 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa
/* MA_RAMP_IN_RESULT is exceptional */
if (ma->rampin_col==MA_RAMP_IN_RESULT) {
/* normal add */
- diff[0] += r * shi->r;
- diff[1] += g * shi->g;
- diff[2] += b * shi->b;
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
}
else {
float colt[3], col[4];
@@ -980,40 +982,37 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa
/* input */
switch (ma->rampin_col) {
case MA_RAMP_IN_ENERGY:
- /* should use 'rgb_to_grayscale' but we only have a vector version */
- fac= 0.3f*r + 0.58f*g + 0.12f*b;
+ fac = IMB_colormanagement_get_luminance(rgb);
break;
case MA_RAMP_IN_SHADER:
- fac= is;
+ fac = is;
break;
case MA_RAMP_IN_NOR:
- fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
+ fac = dot_v3v3(shi->view, shi->vn);
break;
default:
- fac= 0.0f;
+ fac = 0.0f;
break;
}
do_colorband(ma->ramp_col, fac, col);
/* blending method */
- fac= col[3]*ma->rampfac_col;
- colt[0]= shi->r;
- colt[1]= shi->g;
- colt[2]= shi->b;
+ fac = col[3] * ma->rampfac_col;
+ copy_v3_v3(colt, &shi->r);
ramp_blend(ma->rampblend_col, colt, fac, col);
/* output to */
- diff[0] += r * colt[0];
- diff[1] += g * colt[1];
- diff[2] += b * colt[2];
+ diff[0] += rgb[0] * colt[0];
+ diff[1] += rgb[1] * colt[1];
+ diff[2] += rgb[2] * colt[2];
}
}
else {
- diff[0] += r * shi->r;
- diff[1] += g * shi->g;
- diff[2] += b * shi->b;
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
}
}
@@ -1023,7 +1022,7 @@ static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
float col[4];
- float fac = rgb_to_grayscale(spec_col);
+ float fac = IMB_colormanagement_get_luminance(spec_col);
do_colorband(ma->ramp_spec, fac, col);
@@ -1476,26 +1475,51 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
i*= shadfac[3];
shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
}
+ else {
+ shr->shad[3] = 1.0f; /* No shadow at all! */
+ }
}
}
/* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
if (!(lar->mode & LA_NO_DIFF)) {
if (i>0.0f) {
- if (ma->mode & MA_SHADOW_TRA)
- add_to_diffuse(shr->shad, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]);
- else
- add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
+ if (ma->mode & MA_SHADOW_TRA) {
+ const float tcol[3] = {
+ i * shadfac[0] * lacol[0],
+ i * shadfac[1] * lacol[1],
+ i * shadfac[2] * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
+ else {
+ const float tcol[3] = {
+ i * lacol[0],
+ i * lacol[1],
+ i * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
}
/* add light for colored shadow */
if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
- add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]);
+ const float tcol[3] = {
+ lashdw[0] * (i_noshad - i) * lacol[0],
+ lashdw[1] * (i_noshad - i) * lacol[1],
+ lashdw[2] * (i_noshad - i) * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
}
if (i_noshad>0.0f) {
if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) ||
((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW)))
{
- add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
+ const float tcol[3] = {
+ i_noshad * lacol[0],
+ i_noshad * lacol[1],
+ i_noshad * lacol[2]
+ };
+ add_to_diffuse(shr->diff, shi, is, tcol);
}
else {
copy_v3_v3(shr->diff, shr->shad);
@@ -1619,10 +1643,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
/* Old "Shadows Only" */
- accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
+ accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3];
}
else {
- shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy;
+ shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy;
if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
lightness += visifac * lar->energy;
@@ -1671,26 +1695,26 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
if (R.wrld.aomix==WO_AOADD) {
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= f*(1.0f - rgb_to_grayscale(shi->ao));
+ f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao));
shr->alpha= (shr->alpha + f)*f;
}
else {
- shr->alpha -= f*rgb_to_grayscale(shi->ao);
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao);
if (shr->alpha<0.0f) shr->alpha=0.0f;
}
}
else /* AO Multiply */
- shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao));
+ shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao));
}
if (R.wrld.mode & WO_ENV_LIGHT) {
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
+ f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env));
shr->alpha= (shr->alpha + f)*f;
}
else {
f= R.wrld.ao_env_energy*shi->amb;
- shr->alpha -= f*rgb_to_grayscale(shi->env);
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env);
if (shr->alpha<0.0f) shr->alpha=0.0f;
}
}
diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c
index 5261374b34d..a932123243d 100644
--- a/source/blender/render/intern/source/texture_ocean.c
+++ b/source/blender/render/intern/source/texture_ocean.c
@@ -73,7 +73,7 @@ int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres)
return 0;
}
else {
- const int do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
+ const bool do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS) != 0;
int cfra = R.r.cfra;
int retval = TEX_INT;
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index d5c4c407bf6..2c0917243a3 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -41,6 +41,8 @@
#include "RE_shader_ext.h"
+#include "IMB_colormanagement.h"
+
#include "DNA_material_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -504,7 +506,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const
if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- if (rgb_to_luma_y(lacol) < 0.001f) return;
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
}
/* find minimum of volume bounds, or lamp coord */
@@ -538,7 +540,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const
}
}
- if (rgb_to_luma_y(lacol) < 0.001f) return;
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
normalize_v3(lv);
p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
@@ -620,7 +622,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co
if (t0 > t1 * 0.25f) {
/* only use depth cutoff after we've traced a little way into the volume */
- if (rgb_to_luma_y(tr) < shi->mat->vol.depth_cutoff) break;
+ if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
}
vol_get_emission(shi, emit_col, p);
@@ -649,7 +651,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co
add_v3_v3(col, radiance);
/* alpha <-- transmission luminance */
- col[3] = 1.0f - rgb_to_luma_y(tr);
+ col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
}
/* the main entry point for volume shading */
@@ -790,7 +792,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct
copy_v3_v3(shr->combined, tr);
- shr->combined[3] = 1.0f - rgb_to_luma_y(tr);
+ shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
shr->alpha = shr->combined[3];
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 7e8f0e3e9fc..b6628796e0d 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -330,8 +330,8 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
if (my2<my0) return;
@@ -1073,8 +1073,8 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1196,8 +1196,8 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1324,8 +1324,8 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr),
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1426,8 +1426,8 @@ void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1513,7 +1513,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
float x0, y0, x1, y1, x2, y2, z0, z1, z2;
float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
const float *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+ int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2;
/* init */
zbuf_init_span(zspan);
@@ -1526,8 +1526,8 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1574,7 +1574,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
span2= zspan->span1+my2;
}
- for (y=my2; y>=my0; y--, span1--, span2--) {
+ for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
sn1= floor(*span1);
sn2= floor(*span2);
@@ -1583,14 +1583,12 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
if (sn2>=rectx) sn2= rectx-1;
if (sn1<0) sn1= 0;
- u= (double)sn1*uxd + uy0;
- v= (double)sn1*vxd + vy0;
-
- for (x= sn1; x<=sn2; x++, u+=uxd, v+=vxd)
- func(handle, x, y, u, v);
+ u = (((double)sn1 * uxd) + uy0) - (i * uyd);
+ v = (((double)sn1 * vxd) + vy0) - (i * vyd);
- uy0 -= uyd;
- vy0 -= vyd;
+ for (j = 0, x = sn1; x <= sn2; j++, x++) {
+ func(handle, x, y, u + (j * uxd), v + (j * vxd));
+ }
}
}
@@ -2482,8 +2480,8 @@ static void zbuffill_sss(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
if (my2<my0) return;
@@ -2683,8 +2681,8 @@ static void zbuf_fill_in_rgba(ZSpan *zspan, DrawBufPixel *col, float *v1, float
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -3961,7 +3959,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf
float *fp, *col;
int a;
- fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
+ fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname);
if (fp==NULL) return;
col= rectf+3;
@@ -4054,9 +4052,10 @@ 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)
- reset_sky_speedvectors(pa, rl, rl->acolrect?rl->acolrect:rl->rectf); /* if acolrect is set we use it */
-
+ if (rl->layflag & SCE_LAY_SOLID) {
+ float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_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 */
if (pa->crop) {
crop= 1;
@@ -4241,8 +4240,9 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
alpha= samp_shr[a].combined[3];
if (alpha!=0.0f) {
RenderLayer *rl= ssamp.rlpp[a];
-
- addAlphaOverFloat(rl->rectf + 4*od, samp_shr[a].combined);
+
+ float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
add_transp_passes(rl, od, &samp_shr[a], alpha);
if (addpassflag & SCE_PASS_VECTOR)
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 78b5d499644..3f5c86857b7 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/wm_operators.c
intern/wm_subwindow.c
intern/wm_window.c
+ intern/wm_stereo.c
WM_api.h
WM_keymap.h
@@ -78,6 +79,13 @@ set(SRC
wm_window.h
)
+if(WITH_AUDASPACE)
+ list(APPEND INC
+ ../../../intern/audaspace/intern
+ )
+ add_definitions(-DWITH_AUDASPACE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index a6f64f7cdae..912d11762e1 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -32,6 +32,7 @@ sources = env.Glob('intern/*.c')
incs = [
'.',
+ '#/intern/audaspace/intern',
'#/intern/ghost',
'#/intern/guardedalloc',
'#/intern/memutil',
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index d2abfd419d1..bdb373a78ba 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -53,13 +53,11 @@ struct wmEvent;
struct wmEventHandler;
struct wmGesture;
struct wmJob;
-struct wmNotifier;
struct wmOperatorType;
struct wmOperator;
struct rcti;
struct PointerRNA;
struct PropertyRNA;
-struct EnumPropertyItem;
struct MenuType;
struct wmDropBox;
struct wmDrag;
@@ -105,6 +103,7 @@ void WM_window_open_temp (struct bContext *C, struct rcti *position, int type);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
+bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
/* files */
@@ -152,7 +151,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
struct wmEventHandler *WM_event_add_ui_handler(
const struct bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
- void *userdata, const bool accept_dbl_click);
+ void *userdata, const char flag);
void WM_event_remove_ui_handler(
ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
@@ -166,23 +165,42 @@ void WM_event_free_ui_handler_all(
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
+/* handler flag */
+enum {
+ WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */
+ WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 1), /* handler accepts double key press events */
+
+ /* internal */
+ WM_HANDLER_DO_FREE = (1 << 7), /* handler tagged to be freed in wm_handlers_do() */
+};
+
struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes);
/* 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_absolute(const struct wmEvent *event);
/* notifiers */
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
void WM_main_remove_notifier_reference(const void *reference);
+void WM_main_remove_editor_id_reference(const struct ID *id);
/* reports */
+void WM_report_banner_show(const struct bContext *C);
void WM_report(const struct bContext *C, ReportType type, const char *message);
void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void wm_event_add(struct wmWindow *win, const struct wmEvent *event_to_add);
-void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event);
+void wm_event_add_ex(
+ struct wmWindow *win, const struct wmEvent *event_to_add,
+ const struct wmEvent *event_to_add_after)
+ ATTR_NONNULL(1, 2);
+void wm_event_add(
+ struct wmWindow *win, const struct wmEvent *event_to_add)
+ ATTR_NONNULL(1, 2);
+
+void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event);
/* at maximum, every timestep seconds it triggers event_type events */
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index c6c7314e963..fdde28c6bf1 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -101,7 +101,8 @@ int WM_keymap_map_type_get(struct wmKeyMapItem *kmi);
const char *WM_key_event_string(short type);
int WM_key_event_operator_id(
const struct bContext *C, const char *opname, int opcontext,
- struct IDProperty *properties, const bool is_hotkey, struct wmKeyMap **keymap_r);
+ struct IDProperty *properties, const bool is_hotkey,
+ struct wmKeyMap **r_keymap);
char *WM_key_event_operator_string(
const struct bContext *C, const char *opname, int opcontext,
struct IDProperty *properties, const bool is_strict, char *str, int len);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 0e3e65d2e21..109ccc27d79 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -109,7 +109,6 @@ extern "C" {
struct bContext;
struct wmEvent;
struct wmWindowManager;
-struct uiLayout;
struct wmOperator;
struct ImBuf;
@@ -124,17 +123,22 @@ struct ImBuf;
/* ************** wmOperatorType ************************ */
/* flag */
-#define OPTYPE_REGISTER 1 /* register operators in stack after finishing */
-#define OPTYPE_UNDO 2 /* do undo push after after */
-#define OPTYPE_BLOCKING 4 /* let blender grab all input from the WM (X11) */
-#define OPTYPE_MACRO 8
-#define OPTYPE_GRAB_POINTER 16 /* grabs the cursor and optionally enables continuous cursor wrapping */
-#define OPTYPE_PRESET 32 /* show preset menu */
-#define OPTYPE_INTERNAL 64 /* some operators are mainly for internal use
- * and don't make sense to be accessed from the
- * search menu, even if poll() returns true.
- * currently only used for the search toolbox */
-#define OPTYPE_LOCK_BYPASS 128 /* Allow operator to run when interface is locked */
+enum {
+ OPTYPE_REGISTER = (1 << 0), /* register operators in stack after finishing */
+ OPTYPE_UNDO = (1 << 1), /* do undo push after after */
+ OPTYPE_BLOCKING = (1 << 2), /* let blender grab all input from the WM (X11) */
+ OPTYPE_MACRO = (1 << 3),
+ OPTYPE_GRAB_CURSOR = (1 << 4), /* grabs the cursor and optionally enables continuous cursor wrapping */
+ OPTYPE_PRESET = (1 << 5), /* show preset menu */
+
+ /* some operators are mainly for internal use
+ * and don't make sense to be accessed from the
+ * search menu, even if poll() returns true.
+ * currently only used for the search toolbox */
+ OPTYPE_INTERNAL = (1 << 6),
+
+ OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */
+};
/* context to call operator in for WM_operator_name_call */
/* rna_ui.c contains EnumPropertyItem's of these, keep in sync */
@@ -454,7 +458,7 @@ typedef struct wmEvent {
const char *keymap_idname;
/* tablet info, only use when the tablet is active */
- struct wmTabletData *tablet_data;
+ const struct wmTabletData *tablet_data;
/* custom data */
short custom; /* custom data type, stylus, 6dof, see wm_event_types.h */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 34069e0b873..c8ff6dac754 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -228,7 +228,7 @@ uiListType *WM_uilisttype_find(const char *idname, bool quiet)
bool WM_uilisttype_add(uiListType *ult)
{
- BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult);
+ BLI_ghash_insert(uilisttypes_hash, ult->idname, ult);
return 1;
}
@@ -285,7 +285,7 @@ MenuType *WM_menutype_find(const char *idname, bool quiet)
bool WM_menutype_add(MenuType *mt)
{
- BLI_ghash_insert(menutypes_hash, (void *)mt->idname, mt);
+ BLI_ghash_insert(menutypes_hash, mt->idname, mt);
return true;
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 68fd32cb450..d84b65847ca 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -313,21 +313,22 @@ void WM_cursor_time(wmWindow *win, int nr)
}
-/* ******************************************************************
- * Custom Cursor Description:
+/**
+ * Custom Cursor Description
+ * =========================
*
* Each bit represents a pixel, so 1 byte = 8 pixels,
* the bytes go Left to Right. Top to bottom
* the bits in a byte go right to left
* (ie; 0x01, 0x80 represents a line of 16 pix with the first and last pix set.)
*
- * A 0 in the bitmap = bg_color, a 1 fg_color
- * a 0 in the mask = transparent pix.
+ * - A 0 in the bitmap = bg_color, a 1 fg_color
+ * - a 0 in the mask = transparent pix.
*
* Until 32x32 cursors are supported on all platforms, the size of the
* small cursors MUST be 16x16.
*
- * Large cursors have a MAXSIZE of 32x32.
+ * Large cursors have a maximum size of 32x32.
*
* Other than that, the specified size of the cursors is just a guideline,
* However, the char array that defines the BM and MASK must be byte aligned.
@@ -335,18 +336,20 @@ void WM_cursor_time(wmWindow *win, int nr)
* (3 bytes = 17 bits rounded up to nearest whole byte). Pad extra bits
* in mask with 0's.
*
- * Setting big_bm = NULL disables the large version of the cursor.
+ * Setting `big_bm = NULL` disables the large version of the cursor.
*
- * *******************************************************************
+ * ----
*
* There is a nice Python GUI utility that can be used for drawing cursors in
* this format in the Blender source distribution, in
- * blender/source/tools/MakeCursor.py . Start it with $ python MakeCursor.py
- * It will copy its output to the console when you press 'Do it'.
+ * `./source/tools/utils/make_cursor_gui.py` .
*
+ * Start it with the command `python3 make_cursor_gui.py`
+ * It will copy its output to the console when you press 'Do it'.
*/
-/* Because defining a cursor mixes declarations and executable code
+/**
+ * Because defining a cursor mixes declarations and executable code
* each cursor needs it's own scoping block or it would be split up
* over several hundred lines of code. To enforce/document this better
* I define 2 pretty brain-dead macros so it's obvious what the extra "[]"
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 7440570f4a0..16fe9ca5142 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -48,9 +48,11 @@
#include "BIF_gl.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "GHOST_C-api.h"
+#include "ED_node.h"
#include "ED_view3d.h"
#include "ED_screen.h"
@@ -165,6 +167,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
if (ar->swinid) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
}
@@ -175,12 +178,14 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
}
ED_screen_draw(win);
+ win->screen->do_draw = false;
/* draw overlapping regions */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->swinid) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -278,6 +283,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->do_draw) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
@@ -288,6 +294,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->swap == WIN_FRONT_OK) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
@@ -300,7 +307,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
}
}
}
-
+
wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
@@ -308,6 +315,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
/* after area regions so we can do area 'overlay' drawing */
if (screen->do_draw) {
ED_screen_draw(win);
+ win->screen->do_draw = false;
if (exchange)
screen->swap = WIN_FRONT_OK;
@@ -315,6 +323,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
else if (exchange) {
if (screen->swap == WIN_FRONT_OK) {
ED_screen_draw(win);
+ win->screen->do_draw = false;
screen->swap = WIN_BOTH_OK;
}
else if (screen->swap == WIN_BACK_OK)
@@ -328,6 +337,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->swinid && ar->do_draw) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -360,15 +370,6 @@ static void wm_method_draw_damage(bContext *C, wmWindow *win)
/* used. if not, multiple smaller ones are used, with */
/* worst case wasted space being 23.4% for 3x3 textures */
-#define MAX_N_TEX 3
-
-typedef struct wmDrawTriple {
- GLuint bind[MAX_N_TEX * MAX_N_TEX];
- int x[MAX_N_TEX], y[MAX_N_TEX];
- int nx, ny;
- GLenum target;
-} wmDrawTriple;
-
static void split_width(int x, int n, int *splitx, int *nx)
{
int a, newnx, waste;
@@ -405,16 +406,13 @@ static void split_width(int x, int n, int *splitx, int *nx)
}
}
-static void wm_draw_triple_free(wmWindow *win)
+static void wm_draw_triple_free(wmDrawTriple *triple)
{
- if (win->drawdata) {
- wmDrawTriple *triple = win->drawdata;
+ if (triple) {
glDeleteTextures(triple->nx * triple->ny, triple->bind);
MEM_freeN(triple);
-
- win->drawdata = NULL;
}
}
@@ -499,7 +497,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
return 1;
}
-static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
+void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
{
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -571,7 +569,7 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
glBindTexture(triple->target, 0);
}
-static void wm_draw_region_blend(wmWindow *win, ARegion *ar)
+static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple)
{
float fac = ED_region_blend_factor(ar);
@@ -580,7 +578,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar)
wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
- wm_triple_draw_textures(win, win->drawdata, 1.0f - fac);
+ wm_triple_draw_textures(win, triple, 1.0f - fac);
glDisable(GL_BLEND);
}
}
@@ -589,29 +587,46 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrawTriple *triple;
+ wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
bScreen *screen = win->screen;
ScrArea *sa;
ARegion *ar;
- int copytex = 0;
+ int copytex = false;
- if (win->drawdata) {
+ if (drawdata && drawdata->triple) {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, win->drawdata, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
}
else {
- win->drawdata = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+ /* we run it when we start OR when we turn stereo on */
+ if (drawdata == NULL) {
+ drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
+ BLI_addhead(&win->drawdata, drawdata);
+ }
+
+ drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
- if (!wm_triple_gen_textures(win, win->drawdata)) {
+ if (!wm_triple_gen_textures(win, drawdata->triple)) {
wm_draw_triple_fail(C, win);
return;
}
}
- triple = win->drawdata;
+ /* it means stereo was just turned off */
+ /* note: we are removing all drawdatas that are not the first */
+ for (dd = drawdata->next; dd; dd = dd_next) {
+ dd_next = dd->next;
+
+ BLI_remlink(&win->drawdata, dd);
+ wm_draw_triple_free(dd->triple);
+ MEM_freeN(dd);
+ }
+
+ triple = drawdata->triple;
/* draw marked area regions */
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -619,16 +634,17 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid && ar->do_draw) {
-
- if (ar->overlap == 0) {
+
+ if (ar->overlap == false) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_region_set(C, NULL);
- copytex = 1;
+ copytex = true;
}
}
}
-
+
wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
@@ -662,14 +678,15 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* draw overlapping area regions (always like popups) */
for (sa = screen->areabase.first; sa; sa = sa->next) {
CTX_wm_area_set(C, sa);
-
+
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid && ar->overlap) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar);
+
+ wm_draw_region_blend(win, ar, triple);
}
}
@@ -678,12 +695,14 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
+ win->screen->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->swinid) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -691,13 +710,188 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* always draw, not only when screen tagged */
if (win->gesture.first)
wm_gesture_draw(win);
-
+
/* needs pixel coords in screen */
if (wm->drags.first) {
wm_drags_draw(C, win, NULL);
}
}
+static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoViews sview)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmDrawData *drawdata;
+ wmDrawTriple *triple_data, *triple_all;
+ bScreen *screen = win->screen;
+ ScrArea *sa;
+ ARegion *ar;
+ int copytex = false;
+ int id;
+
+ /* we store the triple_data in sequence to triple_all */
+ for (id = 0; id < 2; id++) {
+ drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id);
+
+ if (drawdata && drawdata->triple) {
+ if (id == 0) {
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ wmSubWindowSet(win, screen->mainwin);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ }
+ }
+ else {
+ /* we run it when we start OR when we turn stereo on */
+ if (drawdata == NULL) {
+ drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
+ BLI_addtail(&win->drawdata, drawdata);
+ }
+
+ drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+
+ if (!wm_triple_gen_textures(win, drawdata->triple)) {
+ wm_draw_triple_fail(C, win);
+ return;
+ }
+ }
+ }
+
+ triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple;
+ triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple;
+
+ /* draw marked area regions */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ CTX_wm_area_set(C, sa);
+
+ switch (sa->spacetype) {
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ sima->iuser.multiview_eye = sview;
+ break;
+ }
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = sa->spacedata.first;
+ BGpic *bgpic = v3d->bgpicbase.first;
+ v3d->multiview_eye = sview;
+ if (bgpic) bgpic->iuser.multiview_eye = sview;
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ima->eye = sview;
+ }
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = sa->spacedata.first;
+ sseq->multiview_eye = sview;
+ break;
+ }
+ }
+
+ /* draw marked area regions */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->do_draw) {
+
+ if (ar->overlap == false) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_draw(C, ar);
+
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+
+ CTX_wm_region_set(C, NULL);
+ copytex = true;
+ }
+ }
+ }
+
+ wm_area_mark_invalid_backbuf(sa);
+ CTX_wm_area_set(C, NULL);
+ }
+
+ if (copytex) {
+ wmSubWindowSet(win, screen->mainwin);
+
+ wm_triple_copy_textures(win, triple_data);
+ }
+
+ if (wm->paintcursors.first) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->swinid == screen->subwinactive) {
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* make region ready for draw, scissor, pixelspace */
+ ED_region_set(C, ar);
+ wm_paintcursor_draw(C, ar);
+
+ CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, NULL);
+ }
+ }
+ }
+
+ wmSubWindowSet(win, screen->mainwin);
+ }
+
+ /* draw overlapping area regions (always like popups) */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ CTX_wm_area_set(C, sa);
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->overlap) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_draw(C, ar);
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+ CTX_wm_region_set(C, NULL);
+
+ wm_draw_region_blend(win, ar, triple_data);
+ }
+ }
+
+ CTX_wm_area_set(C, NULL);
+ }
+
+ /* after area regions so we can do area 'overlay' drawing */
+ ED_screen_draw(win);
+ if (sview == STEREO_RIGHT_ID)
+ win->screen->do_draw = false;
+
+ /* draw floating regions (menus) */
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid) {
+ CTX_wm_menu_set(C, ar);
+ ED_region_do_draw(C, ar);
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+ CTX_wm_menu_set(C, NULL);
+ }
+ }
+
+ /* always draw, not only when screen tagged */
+ if (win->gesture.first)
+ wm_gesture_draw(win);
+
+ /* needs pixel coords in screen */
+ if (wm->drags.first) {
+ wm_drags_draw(C, win, NULL);
+ }
+
+ /* copy the ui + overlays */
+ wmSubWindowSet(win, screen->mainwin);
+ wm_triple_copy_textures(win, triple_all);
+}
/****************** main update call **********************/
@@ -848,8 +1042,16 @@ void wm_draw_update(bContext *C)
wm_method_draw_overlap_all(C, win, 0);
else if (drawmethod == USER_DRAW_OVERLAP_FLIP)
wm_method_draw_overlap_all(C, win, 1);
- else // if (drawmethod == USER_DRAW_TRIPLE)
- wm_method_draw_triple(C, win);
+ else { /* USER_DRAW_TRIPLE */
+ if ((WM_stereo3d_enabled(win, false)) == false) {
+ wm_method_draw_triple(C, win);
+ }
+ else {
+ wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID);
+ wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID);
+ wm_method_draw_stereo3d(C, win);
+ }
+ }
win->screen->do_draw_gesture = false;
win->screen->do_draw_paintcursor = false;
@@ -862,15 +1064,23 @@ void wm_draw_update(bContext *C)
}
}
+void wm_draw_data_free(wmWindow *win)
+{
+ wmDrawData *dd;
+
+ for (dd = win->drawdata.first; dd; dd = dd->next) {
+ wm_draw_triple_free(dd->triple);
+ }
+ BLI_freelistN(&win->drawdata);
+}
+
void wm_draw_window_clear(wmWindow *win)
{
bScreen *screen = win->screen;
ScrArea *sa;
ARegion *ar;
- int drawmethod = wm_automatic_draw_method(win);
- if (drawmethod == USER_DRAW_TRIPLE)
- wm_draw_triple_free(win);
+ wm_draw_data_free(win);
/* clear screen swap flags */
if (screen) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f1a46826435..075390f9a15 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -63,6 +63,7 @@
#include "ED_fileselect.h"
#include "ED_info.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
@@ -96,7 +97,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
/* ************ event management ************** */
-void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
+void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
{
wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
@@ -104,7 +105,18 @@ void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
update_tablet_data(win, event);
- BLI_addtail(&win->queue, event);
+ if (event_to_add_after == NULL) {
+ BLI_addtail(&win->queue, event);
+ }
+ else {
+ /* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */
+ BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event);
+ }
+}
+
+void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
+{
+ wm_event_add_ex(win, event_to_add, NULL);
}
void wm_event_free(wmEvent *event)
@@ -123,7 +135,7 @@ void wm_event_free(wmEvent *event)
}
if (event->tablet_data) {
- MEM_freeN(event->tablet_data);
+ MEM_freeN((void *)event->tablet_data);
}
MEM_freeN(event);
@@ -217,6 +229,7 @@ void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G.main;
wmWindowManager *wm = bmain->wm.first;
+
if (wm) {
wmNotifier *note, *note_next;
@@ -232,6 +245,24 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
+void WM_main_remove_editor_id_reference(const ID *id)
+{
+ Main *bmain = G.main;
+ bScreen *sc;
+
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ ED_spacedata_id_unref(sl, id);
+ }
+ }
+ }
+}
+
static void wm_notifier_clear(wmNotifier *note)
{
/* NULL the entire notifier, only leaving (next, prev) members intact */
@@ -293,7 +324,7 @@ void wm_event_do_notifiers(bContext *C)
do_anim = true;
}
}
- if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
+ if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
ED_info_stats_clear(win->screen->scene);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
@@ -535,10 +566,9 @@ void WM_event_print(const wmEvent *event)
RNA_enum_identifier(event_type_items, event->type, &type_id);
RNA_enum_identifier(event_value_items, event->val, &val_id);
- printf("wmEvent type:%d / %s, val:%d / %s, \n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, \n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', "
- " keymap_idname:%s, pointer:%p\n",
+ printf("wmEvent type:%d / %s, val:%d / %s,\n"
+ " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
+ " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n",
event->type, type_id, event->val, val_id,
event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
event->x, event->y, event->ascii,
@@ -548,17 +578,19 @@ void WM_event_print(const wmEvent *event)
if (ISNDOF(event->type)) {
const wmNDOFMotionData *ndof = event->customdata;
if (event->type == NDOF_MOTION) {
- printf(" ndof: rot: (%.4f %.4f %.4f),\n"
- " tx: (%.4f %.4f %.4f),\n"
- " dt: %.4f, progress: %d\n",
- UNPACK3(ndof->rvec),
- UNPACK3(ndof->tvec),
- ndof->dt, ndof->progress);
+ printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
+ UNPACK3(ndof->rvec), UNPACK3(ndof->tvec), ndof->dt, ndof->progress);
}
else {
/* ndof buttons printed already */
}
}
+
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
+ wmtab->Active, wmtab->Pressure, wmtab->Xtilt, wmtab->Ytilt);
+ }
}
else {
printf("wmEvent - NULL\n");
@@ -567,26 +599,40 @@ void WM_event_print(const wmEvent *event)
#endif /* NDEBUG */
+/**
+ * Show the report in the info header.
+ */
+void WM_report_banner_show(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ReportList *wm_reports = CTX_wm_reports(C);
+ ReportTimerInfo *rti;
+
+ /* After adding reports to the global list, reset the report timer. */
+ WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+
+ /* Records time since last report was added */
+ wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05);
+
+ rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ wm_reports->reporttimer->customdata = rti;
+}
+
+bool WM_event_is_absolute(const wmEvent *event)
+{
+ return (event->tablet_data != NULL);
+}
+
static void wm_add_reports(const bContext *C, ReportList *reports)
{
/* if the caller owns them, handle this */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
-
- wmWindowManager *wm = CTX_wm_manager(C);
ReportList *wm_reports = CTX_wm_reports(C);
- ReportTimerInfo *rti;
/* add reports to the global list, otherwise they are not seen */
BLI_movelisttolist(&wm_reports->list, &reports->list);
-
- /* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
-
- /* Records time since last report was added */
- wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm_reports->reporttimer->customdata = rti;
+
+ WM_report_banner_show(C);
}
}
@@ -662,7 +708,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
wm_add_reports(C, op->reports);
}
-/* this function is mainly to check that the rules for freeing
+/**
+ * This function is mainly to check that the rules for freeing
* an operator are kept in sync.
*/
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
@@ -781,23 +828,29 @@ int WM_operator_call(bContext *C, wmOperator *op)
return WM_operator_call_ex(C, op, false);
}
-/* this is intended to be used when an invoke operator wants to call exec on its self
+/**
+ * This is intended to be used when an invoke operator wants to call exec on its self
* and is basically like running op->type->exec() directly, no poll checks no freeing,
- * since we assume whoever called invoke will take care of that */
+ * since we assume whoever called invoke will take care of that
+ */
int WM_operator_call_notest(bContext *C, wmOperator *op)
{
return wm_operator_exec_notest(C, op);
}
-/* do this operator again, put here so it can share above code */
+/**
+ * Execute this operator again, put here so it can share above code
+ */
int WM_operator_repeat(bContext *C, wmOperator *op)
{
return wm_operator_exec(C, op, true, true);
}
-/* true if WM_operator_repeat can run
+/**
+ * \return true if #WM_operator_repeat can run
* simple check for now but may become more involved.
- * To be sure the operator can run call WM_operator_poll(C, op->type) also, since this call
- * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. */
+ * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
+ * checks if WM_operator_repeat() can run at all, not that it WILL run at any time.
+ */
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
if (op->type->exec != NULL) {
@@ -1003,8 +1056,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
#endif
-static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
- PointerRNA *properties, ReportList *reports, const bool poll_only)
+static int wm_operator_invoke(
+ bContext *C, wmOperatorType *ot, wmEvent *event,
+ PointerRNA *properties, ReportList *reports, const bool poll_only)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -1083,13 +1137,16 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
int bounds[4] = {-1, -1, -1, -1};
bool wrap;
- if (op->opm) {
+ if (event == NULL) {
+ wrap = false;
+ }
+ else if (op->opm) {
wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
- ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
+ ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR));
}
else {
wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
- ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
+ ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR));
}
/* exception, cont. grab in header is annoying */
@@ -1101,16 +1158,16 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
}
if (wrap) {
- rcti *winrect = NULL;
+ const rcti *winrect = NULL;
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
- if (ar && ar->regiontype == RGN_TYPE_WINDOW && event &&
+ if (ar && ar->regiontype == RGN_TYPE_WINDOW &&
BLI_rcti_isect_pt_v(&ar->winrct, &event->x))
{
winrect = &ar->winrct;
}
- else if (sa) {
+ else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) {
winrect = &sa->totrct;
}
@@ -1139,12 +1196,15 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
return retval;
}
-/* WM_operator_name_call is the main accessor function
+/**
+ * #WM_operator_name_call is the main accessor function
* this is for python to access since its done the operator lookup
*
- * invokes operator in context */
-static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
- const short context, const bool poll_only)
+ * invokes operator in context
+ */
+static int wm_operator_call_internal(
+ bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
+ const short context, const bool poll_only)
{
wmEvent *event;
@@ -1153,7 +1213,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
CTX_wm_operator_poll_msg_set(C, NULL);
/* dummie test */
- if (ot && C) {
+ if (ot) {
wmWindow *window = CTX_wm_window(C);
switch (context) {
@@ -1284,13 +1344,16 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin
return 0;
}
-/* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
- * - wmOperatorType is used instead of operator name since python already has the operator type
- * - poll() must be called by python before this runs.
- * - reports can be passed to this function (so python can report them as exceptions)
+/**
+ * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
+ *
+ * - #wmOperatorType is used instead of operator name since python already has the operator type.
+ * - `poll()` must be called by python before this runs.
+ * - reports can be passed to this function (so python can report them as exceptions).
*/
-int WM_operator_call_py(bContext *C, wmOperatorType *ot, short context,
- PointerRNA *properties, ReportList *reports, const bool is_undo)
+int WM_operator_call_py(
+ bContext *C, wmOperatorType *ot, short context,
+ PointerRNA *properties, ReportList *reports, const bool is_undo)
{
int retval = OPERATOR_CANCELLED;
@@ -1337,7 +1400,7 @@ void wm_event_free_handler(wmEventHandler *handler)
}
/* only set context when area/region is part of screen */
-static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
+static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1358,10 +1421,27 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
}
else {
ARegion *ar;
+ wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
CTX_wm_area_set(C, sa);
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar == handler->op_region)
- break;
+
+ if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
+ ar = BKE_area_find_region_xy(sa, handler->op_region_type, event->x, event->y);
+ if (ar) {
+ handler->op_region = ar;
+ }
+ }
+ else {
+ ar = NULL;
+ }
+
+ if (ar == NULL) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar == handler->op_region) {
+ break;
+ }
+ }
+ }
+
/* XXX no warning print here, after full-area and back regions are remade */
if (ar)
CTX_wm_region_set(C, ar);
@@ -1379,11 +1459,12 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
/* C is zero on freeing database, modal handlers then already were freed */
while ((handler = BLI_pophead(handlers))) {
if (handler->op) {
+ wmWindow *win = CTX_wm_window(C);
if (handler->op->type->cancel) {
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, win->eventstate);
if (handler->op->type->flag & OPTYPE_UNDO)
wm->op_undo_depth++;
@@ -1397,7 +1478,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
CTX_wm_region_set(C, region);
}
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ WM_cursor_grab_disable(win, NULL);
WM_operator_free(handler->op);
}
else if (handler->ui_remove) {
@@ -1515,7 +1596,8 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
}
}
-/* Check whether operator is allowed to run in case interface is locked,
+/**
+ * Check whether operator is allowed to run in case interface is locked,
* If interface is unlocked, will always return truth.
*/
static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
@@ -1569,7 +1651,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
ARegion *region = CTX_wm_region(C);
bool dbl_click_disabled = false;
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
@@ -1714,10 +1796,14 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
BLI_remlink(handlers, handler);
if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
- ED_screen_full_prevspace(C, CTX_wm_area(C));
+ ScrArea *sa = CTX_wm_area(C);
+ const SpaceLink *sl = sa->spacedata.first;
+ const bool was_prev_temp = (sl->next && sl->next->spacetype == SPACE_IMAGE);
+
+ ED_screen_full_prevspace(C, sa, was_prev_temp);
}
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
/* needed for UI_popup_menu_reports */
@@ -1843,7 +1929,7 @@ static int wm_action_not_handled(int action)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
#ifndef NDEBUG
- const int do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
+ const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
/* comment this out to flood the console! (if you really want to test) */
!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
;
@@ -2223,7 +2309,7 @@ void wm_event_do_handlers(bContext *C)
Scene *scene = win->screen->scene;
if (scene) {
- int is_playing_sound = sound_scene_playing(win->screen->scene);
+ int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
if (is_playing_sound != -1) {
bool is_playing_screen;
@@ -2240,7 +2326,7 @@ void wm_event_do_handlers(bContext *C)
}
if (is_playing_sound == 0) {
- const float time = sound_sync_scene(scene);
+ const float time = BKE_sound_sync_scene(scene);
if (finite(time)) {
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
@@ -2330,6 +2416,11 @@ void wm_event_do_handlers(bContext *C)
break;
}
+ /* update azones if needed - done here because it needs to be independent from redraws */
+ if (sa->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
+ ED_area_azones_update(sa, &event->x);
+ }
+
if (wm_event_inside_i(event, &sa->totrct)) {
CTX_wm_area_set(C, sa);
@@ -2391,7 +2482,7 @@ void wm_event_do_handlers(bContext *C)
/* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad?
* doing it on ghost queue gives errors when mousemoves go over area borders */
- if (doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
+ if (doit && win->screen->subwinactive != win->screen->mainwin) {
win->eventstate->prevx = event->x;
win->eventstate->prevy = event->y;
//printf("win->eventstate->prev = %d %d\n", event->x, event->y);
@@ -2448,11 +2539,12 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
/* operator is supposed to have a filled "path" property */
/* optional property: filetype (XXX enum?) */
-/* Idea is to keep a handler alive on window queue, owning the operator.
+/**
+ * The idea here is to keep a handler alive on window queue, owning the operator.
* The filewindow can send event to make it execute, thus ensuring
* executing happens outside of lower level queues, with UI refreshed.
- * Should also allow multiwin solutions */
-
+ * Should also allow multiwin solutions
+ */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmEventHandler *handler, *handlernext;
@@ -2529,6 +2621,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
handler->op_area = CTX_wm_area(C); /* means frozen screen context for modal handlers! */
handler->op_region = CTX_wm_region(C);
+ handler->op_region_type = handler->op_region ? handler->op_region->regiontype : -1;
BLI_addhead(&win->modalhandlers, handler);
@@ -2597,7 +2690,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmEventHandler *WM_event_add_ui_handler(
const bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
- void *userdata, const bool accept_dbl_click)
+ void *userdata, const char flag)
{
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler");
handler->ui_handle = ui_handle;
@@ -2614,9 +2707,8 @@ wmEventHandler *WM_event_add_ui_handler(
handler->ui_menu = NULL;
}
- if (accept_dbl_click) {
- handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK;
- }
+ BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
+ handler->flag = flag;
BLI_addhead(handlers, handler);
@@ -2842,52 +2934,41 @@ static int convert_key(GHOST_TKey key)
static void wm_eventemulation(wmEvent *event)
{
- /* Store last mmb event value to make emulation work when modifier keys are released first. */
- static int mmb_emulated = 0; /* this should be in a data structure somwhere */
+ /* Store last mmb/rmb event value to make emulation work when modifier keys
+ * are released first. This really should be in a data structure somewhere. */
+ static int emulating_event = EVENT_NONE;
- /* middlemouse emulation */
+ /* middlemouse and rightmouse emulation */
if (U.flag & USER_TWOBUTTONMOUSE) {
if (event->type == LEFTMOUSE) {
if (event->val == KM_PRESS && event->alt) {
event->type = MIDDLEMOUSE;
event->alt = 0;
- mmb_emulated = 1;
- }
- else if (event->val == KM_RELEASE) {
- /* only send middle-mouse release if emulated */
- if (mmb_emulated) {
- event->type = MIDDLEMOUSE;
- event->alt = 0;
- }
- mmb_emulated = 0;
+ emulating_event = MIDDLEMOUSE;
}
- }
-
- }
-
#ifdef __APPLE__
-
- /* rightmouse emulation */
- if (U.flag & USER_TWOBUTTONMOUSE) {
- if (event->type == LEFTMOUSE) {
-
- if (event->val == KM_PRESS && event->oskey) {
+ else if (event->val == KM_PRESS && event->oskey) {
event->type = RIGHTMOUSE;
event->oskey = 0;
- mmb_emulated = 1;
+ emulating_event = RIGHTMOUSE;
}
+#endif
else if (event->val == KM_RELEASE) {
- if (mmb_emulated) {
- event->oskey = RIGHTMOUSE;
+ /* only send middle-mouse release if emulated */
+ if (emulating_event == MIDDLEMOUSE) {
+ event->type = MIDDLEMOUSE;
event->alt = 0;
}
- mmb_emulated = 0;
+ else if (emulating_event == RIGHTMOUSE) {
+ event->type = RIGHTMOUSE;
+ event->oskey = 0;
+ }
+ emulating_event = EVENT_NONE;
}
}
}
-#endif
/* numpad emulation */
if (U.flag & USER_NONUMPAD) {
@@ -3109,7 +3190,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.x = evt->x = pd->x;
event.y = evt->y = pd->y;
- event.val = 0;
+ event.val = KM_NOTHING;
/* Use prevx/prevy so we can calculate the delta later */
event.prevx = event.x - pd->deltaX;
@@ -3337,7 +3418,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.type = TIMER;
event.custom = EVT_DATA_TIMER;
event.customdata = customdata;
- event.val = 0;
+ event.val = KM_NOTHING;
event.keymodifier = 0;
wm_event_add(win, &event);
@@ -3347,7 +3428,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventNDOFMotion:
{
event.type = NDOF_MOTION;
- event.val = 0;
+ event.val = KM_NOTHING;
attach_ndof_data(&event, customdata);
wm_event_add(win, &event);
@@ -3504,7 +3585,7 @@ float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
zero_v2(tilt);
if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ const wmTabletData *wmtab = event->tablet_data;
erasor = (wmtab->Active == EVT_TABLET_ERASER);
if (wmtab->Active != EVT_TABLET_NONE) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index f5a7ad164d6..5bd2bb88f84 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -301,7 +301,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
UI_init_userdef();
MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
- sound_init(bmain);
+ BKE_sound_init(bmain);
/* needed so loading a file from the command line respects user-pref [#26156] */
BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI);
@@ -506,13 +506,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
#endif
- BKE_reset_undo();
- BKE_write_undo(C, "original"); /* save current state */
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
success = true;
}
else if (retval == BKE_READ_EXOTIC_OK_OTHER)
- BKE_write_undo(C, "Import file");
+ BKE_undo_write(C, "Import file");
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -660,8 +660,8 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
// refresh_interface_font();
// undo_editmode_clear();
- BKE_reset_undo();
- BKE_write_undo(C, "original"); /* save current state */
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
ED_editors_init(C);
DAG_on_visible_update(CTX_data_main(C), true);
@@ -846,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, err_out);
+ IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, false, R_ALPHAPREMUL, err_out);
+ IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
}
if (ibuf) {
@@ -860,7 +860,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
/* add pretty overlay */
- IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
+ IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect);
/* first write into thumb buffer */
thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
@@ -951,7 +951,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
/* operator now handles overwrite checks */
if (G.fileflags & G_AUTOPACK) {
- packAll(G.main, reports);
+ packAll(G.main, reports, false);
}
/* don't forget not to return without! */
@@ -991,7 +991,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
/* run this function after because the file cant be written before the blend is */
if (ibuf_thumb) {
IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
- ibuf_thumb = IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
+ ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
IMB_freeImBuf(ibuf_thumb);
}
@@ -1086,7 +1086,7 @@ void wm_autosave_location(char *filepath)
if (G.main && G.relbase_valid) {
const char *basename = BLI_path_basename(G.main->name);
int len = strlen(basename) - 6;
- BLI_snprintf(path, sizeof(path), "%.*s-%d.blend", len, basename, pid);
+ BLI_snprintf(path, sizeof(path), "%.*s.blend", len, basename);
}
else {
BLI_snprintf(path, sizeof(path), "%d.blend", pid);
@@ -1137,8 +1137,6 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
}
}
- ED_editors_flush_edits(C, false);
-
wm_autosave_location(filepath);
if (U.uiflag & USER_GLOBALUNDO) {
@@ -1149,6 +1147,8 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
/* save as regular blend file */
int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
+ ED_editors_flush_edits(C, false);
+
/* no error reporting to console */
BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 9778f1651de..edca1f97ecf 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -58,9 +58,10 @@
#include "BKE_screen.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_mball.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
#include "BKE_report.h"
@@ -149,9 +150,11 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
- set_free_windowmanager_cb(wm_close_and_free); /* library.c */
- set_free_notifier_reference_cb(WM_main_remove_notifier_reference); /* library.c */
- set_blender_test_break_cb(wm_window_testbreak); /* blender.c */
+ BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
+ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
+ BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */
+ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
+ BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
@@ -170,6 +173,25 @@ void WM_init(bContext *C, int argc, const char **argv)
BLF_lang_set(NULL);
+ if (!G.background) {
+ GPU_init();
+
+ GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
+ GPU_set_linear_mipmap(true);
+ GPU_set_anisotropic(U.anisotropic_filter);
+ GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
+
+ UI_init();
+ }
+ else {
+ /* Note: Currently only inits icons, which we now want in background mode too
+ * (scripts could use those in background processing...).
+ * In case we do more later, we may need to pass a 'background' flag.
+ * Called from 'UI_init' above */
+ BKE_icons_init(1);
+ }
+
+
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -195,16 +217,6 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_init_reports(C); /* reports cant be initialized before the wm */
- if (!G.background) {
- GPU_init();
-
- GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
- GPU_set_anisotropic(U.anisotropic_filter);
- GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
-
- UI_init();
- }
-
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
@@ -327,7 +339,7 @@ bool WM_init_game(bContext *C)
WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL);
- sound_exit();
+ BKE_sound_exit();
return true;
}
@@ -397,7 +409,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
- sound_exit();
+ 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? */
@@ -406,7 +418,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
wmWindow *win;
if (!G.background) {
- if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) {
+ if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) {
/* save the undo state as quit.blend */
char filename[FILE_MAX];
bool has_edited;
@@ -516,7 +528,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
GPU_exit();
}
- BKE_reset_undo();
+ BKE_undo_reset();
ED_file_exit(); /* for fsmenu */
@@ -538,7 +550,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
if (MEM_get_memory_blocks_in_use() != 0) {
size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
- printf("Error: Not freed memory blocks: %d, total unfreed memory %f MB\n",
+ printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
MEM_get_memory_blocks_in_use(),
(double)mem_in_use / 1024 / 1024);
MEM_printmemlist();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 6bc858e861a..f8258d18c1a 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -157,8 +157,8 @@ static void wm_job_main_thread_yield(wmJob *wm_job, bool ending)
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
}
-/* finds:
- * if type or owner, compare for it, otherwise any matching job
+/**
+ * Finds if type or owner, compare for it, otherwise any matching job.
*/
static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
{
@@ -185,9 +185,12 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
/* ******************* public API ***************** */
-/* returns current or adds new job, but doesnt run it */
-/* every owner only gets a single job, adding a new one will stop running job and
- * when stopped it starts the new one */
+/**
+ * \return current job or adds new job, but doesnt run it.
+ *
+ * \note every owner only gets a single job,
+ * adding a new one will stop running job and when stopped it starts the new one.
+ */
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
{
wmJob *wm_job = wm_job_find(wm, owner, job_type);
@@ -375,8 +378,10 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
// if (suspend) printf("job suspended: %s\n", test->name);
}
-/* if job running, the same owner gave it a new job */
-/* if different owner starts existing startjob, it suspends itself */
+/**
+ * if job running, the same owner gave it a new job.
+ * if different owner starts existing startjob, it suspends itself
+ */
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 82e46c1b333..45177903cce 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -546,7 +546,7 @@ static void wm_keymap_diff(wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km
if (to_kmi) {
orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id);
- if (!orig_kmi)
+ if (!orig_kmi && addon_km)
orig_kmi = wm_keymap_find_item_equals(addon_km, kmi);
if (orig_kmi) {
@@ -929,7 +929,8 @@ int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len)
static wmKeyMapItem *wm_keymap_item_find_handlers(
const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
- IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_strict, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmEventHandler *handler;
@@ -966,7 +967,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
#endif
if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) {
- if (keymap_r) *keymap_r = keymap;
+ if (r_keymap) *r_keymap = keymap;
return kmi;
}
/* Debug only, helps spotting mismatches between menu entries and shortcuts! */
@@ -989,11 +990,13 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
"this might not be desired!\n", opname);
printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str);
#ifndef NDEBUG
+#ifdef WITH_PYTHON
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
IDP_spit(kmi->ptr->data);
#endif
+#endif
printf("\n");
}
@@ -1004,7 +1007,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
}
}
else {
- if (keymap_r) *keymap_r = keymap;
+ if (r_keymap) *r_keymap = keymap;
return kmi;
}
}
@@ -1013,13 +1016,14 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
}
/* ensure un-initialized keymap is never used */
- if (keymap_r) *keymap_r = NULL;
+ if (r_keymap) *r_keymap = NULL;
return NULL;
}
static wmKeyMapItem *wm_keymap_item_find_props(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_strict, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
@@ -1028,10 +1032,10 @@ static wmKeyMapItem *wm_keymap_item_find_props(
/* look into multiple handler lists to find the item */
if (win)
- found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
if (sa && found == NULL)
- found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
if (found == NULL) {
if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
@@ -1040,7 +1044,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
@@ -1048,18 +1052,18 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW))
ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
else {
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
}
@@ -1068,7 +1072,8 @@ static wmKeyMapItem *wm_keymap_item_find_props(
static wmKeyMapItem *wm_keymap_item_find(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_hotkey, bool is_strict, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_hotkey, bool is_strict,
+ wmKeyMap **r_keymap)
{
wmKeyMapItem *found;
@@ -1081,7 +1086,7 @@ static wmKeyMapItem *wm_keymap_item_find(
is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0);
}
- found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
/* This block is *only* useful in one case: when op uses an enum menu in its prop member
* (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle,
@@ -1105,7 +1110,7 @@ static wmKeyMapItem *wm_keymap_item_find(
RNA_property_unset(&opptr, ot->prop);
found = wm_keymap_item_find_props(C, opname, opcontext, properties_temp,
- is_strict, is_hotkey, keymap_r);
+ is_strict, is_hotkey, r_keymap);
}
IDP_FreeProperty(properties_temp);
@@ -1134,11 +1139,13 @@ static wmKeyMapItem *wm_keymap_item_find(
"this might not be desired!\n", opname);
printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str);
#ifndef NDEBUG
+#ifdef WITH_PYTHON
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
IDP_spit(kmi->ptr->data);
#endif
+#endif
printf("\n");
}
@@ -1167,9 +1174,10 @@ char *WM_key_event_operator_string(
int WM_key_event_operator_id(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
- wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, keymap_r);
+ wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap);
if (kmi)
return kmi->id;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 6f9646f35a1..66dd851fc91 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -172,6 +172,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot);
if (ot->name == NULL) {
@@ -194,6 +195,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_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);
@@ -339,7 +341,9 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
* */
if (op->opm->type->flag & OPTYPE_BLOCKING) {
int bounds[4] = {-1, -1, -1, -1};
- int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
+ const bool wrap = (
+ (U.uiflag & USER_CONTINUOUS_MOUSE) &&
+ ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR)));
if (wrap) {
ARegion *ar = CTX_wm_region(C);
@@ -374,6 +378,7 @@ static void wm_macro_cancel(bContext *C, wmOperator *op)
wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag)
{
wmOperatorType *ot;
+ const char *i18n_context;
if (WM_operatortype_find(idname, true)) {
printf("%s: macro error: operator %s exists\n", __func__, idname);
@@ -400,8 +405,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
- RNA_def_struct_translation_context(ot->srna, ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) :
- BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ RNA_def_struct_translation_context(ot->srna, i18n_context);
+ ot->translation_context = i18n_context;
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -427,6 +433,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
@@ -486,7 +493,7 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot)
if (ot->macro.first)
wm_operatortype_free_macro(ot);
- BLI_ghash_remove(global_ops_hash, (void *)ot->idname, NULL, NULL);
+ BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
WM_keyconfig_update_operatortype();
@@ -570,12 +577,13 @@ void WM_operator_bl_idname(char *to, const char *from)
to[0] = 0;
}
-/* Print a string representation of the operator, with the args that it runs so python can run it again.
+/**
+ * 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:
- * WM_operator_pystring(C, op);
+ * `WM_operator_pystring(C, op);`
*
- * Note: both op and opptr may be NULL (op is only used for macro operators).
+ * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
*/
char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args,
wmOperatorType *ot, PointerRNA *opptr)
@@ -1263,6 +1271,13 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type,
if (flag & WM_FILESEL_RELPATH)
RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
+ if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) {
+ prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -1392,7 +1407,7 @@ bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
- return !(ED_undo_valid(C, idname) == 0 || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
+ return !((ED_undo_is_valid(C, idname) == false) || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
}
wmOperator *WM_operator_last_redo(const bContext *C)
@@ -1502,7 +1517,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
UI_block_flag_disable(block, UI_BLOCK_LOOP);
- UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
+ /* UI_BLOCK_NUMSELECT for layer buttons */
+ UI_block_flag_enable(block, UI_BLOCK_NUMSELECT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
/* if register is not enabled, the operator gets freed on OPERATOR_FINISHED
* ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */
@@ -1539,6 +1555,9 @@ typedef struct wmOpPopUp {
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
wmOpPopUp *data = arg1;
uiBlock *block = arg2;
@@ -1551,7 +1570,11 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
/* in this case, wm_operator_ui_popup_cancel wont run */
MEM_freeN(data);
- UI_popup_block_close(C, block);
+ /* check window before 'block->handle' incase the
+ * popup execution closed the window and freed the block. see T44688. */
+ if (BLI_findindex(&wm->windows, win) != -1) {
+ UI_popup_block_close(C, win, block);
+ }
}
static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
@@ -1708,18 +1731,20 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
return OPERATOR_RUNNING_MODAL;
}
-/* Same as WM_operator_props_popup but don't use operator redo.
- * just wraps WM_operator_props_dialog_popup.
+/**
+ * Same as #WM_operator_props_popup but don't use operator redo.
+ * just wraps #WM_operator_props_dialog_popup.
*/
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, false, false);
}
-/* Same as WM_operator_props_popup but call the operator first,
+/**
+ * Same as #WM_operator_props_popup but call the operator first,
* This way - the button values correspond to the result of the operator.
- * Without this, first access to a button will make the result jump,
- * see [#32452] */
+ * Without this, first access to a button will make the result jump, see T32452.
+ */
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, true, true);
@@ -1823,21 +1848,16 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
{
- UI_popup_block_close(C, arg_block);
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
}
static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
-/* XXX: hack to refresh splash screen with updated preset menu name,
- * since popup blocks don't get regenerated like panels do */
-static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_block), void *UNUSED(arg))
+static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg))
{
- /* ugh, causes crashes in other buttons, disabling for now until
- * a better fix */
-#if 0
- UI_popup_block_close(C, arg_block);
- UI_popup_block_invoke(C, wm_block_create_splash, NULL);
-#endif
+ ARegion *ar_menu = CTX_wm_menu(C);
+ ED_region_tag_refresh_ui(ar_menu);
}
static int wm_resource_check_prev(void)
@@ -1919,7 +1939,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
/* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
* with the OS when the splash shows, window clipping in this case gives
* ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */
- UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
/* XXX splash scales with pixelsize, should become widget-units */
but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */
@@ -1985,8 +2005,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
uiItemL(col, IFACE_("Links"), ICON_NONE);
+#if 0
uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
"https://cloud.blender.org/join");
+#endif
uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url",
"http://www.blender.org/foundation/donation-payment/");
uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url",
@@ -2440,18 +2462,18 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
uiLayout *layout = op->layout;
uiLayout *col = op->layout;
- const char *autoexec_text = NULL;
+ const char *autoexec_text;
uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
if (file_info->is_untrusted) {
- autoexec_text = "Trusted Source [Untrusted Path]";
+ autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
uiLayoutSetActive(col, false);
uiLayoutSetEnabled(col, false);
}
else {
- autoexec_text = "Trusted Source";
+ autoexec_text = IFACE_("Trusted Source");
}
uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
@@ -2865,30 +2887,45 @@ static void wm_filepath_default(char *filepath)
static void save_set_compress(wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "compress")) {
- if (G.save_over) /* keep flag for existing file */
- RNA_boolean_set(op->ptr, "compress", (G.fileflags & G_FILE_COMPRESS) != 0);
- else /* use userdef for new file */
- RNA_boolean_set(op->ptr, "compress", (U.flag & USER_FILECOMPRESS) != 0);
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "compress");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ if (G.save_over) { /* keep flag for existing file */
+ RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
+ }
+ else { /* use userdef for new file */
+ RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
+ }
}
}
-static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static void save_set_filepath(wmOperator *op)
{
+ PropertyRNA *prop;
char name[FILE_MAX];
- save_set_compress(op);
-
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
+ prop = RNA_struct_find_property(op->ptr, "filepath");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* if not saved before, get the name of the most recently used .blend file */
+ if (G.main->name[0] == 0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+ }
+
+ wm_filepath_default(name);
+ RNA_property_string_set(op->ptr, prop, name);
}
- else
- BLI_strncpy(name, G.main->name, FILE_MAX);
-
- wm_filepath_default(name);
- RNA_string_set(op->ptr, "filepath", name);
+}
+
+static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+
+ save_set_compress(op);
+ save_set_filepath(op);
WM_event_add_fileselect(C, op);
@@ -2987,7 +3024,6 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- char name[FILE_MAX];
int ret;
/* cancel if no active window */
@@ -2995,18 +3031,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_CANCELLED;
save_set_compress(op);
-
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
- }
- else
- BLI_strncpy(name, G.main->name, FILE_MAX);
-
- wm_filepath_default(name);
-
- RNA_string_set(op->ptr, "filepath", name);
+ save_set_filepath(op);
/* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
* enable the option to remap paths to avoid confusion [#37240] */
@@ -3018,8 +3043,11 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
}
if (G.save_over) {
- if (BLI_exists(name)) {
- ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, name);
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ if (BLI_exists(path)) {
+ ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
}
else {
ret = wm_save_as_mainfile_exec(C, op);
@@ -3144,9 +3172,10 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle)
/* **************** Border gesture *************** */
-/* Border gesture has two types:
- * 1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border
- * 2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends
+/**
+ * Border gesture has two types:
+ * -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border.
+ * -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends.
*
* It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type)
*/
@@ -3445,7 +3474,10 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event)
tevent.type = EVT_TWEAK_M;
tevent.val = val;
/* mouse coords! */
- wm_event_add(window, &tevent);
+
+ /* important we add immediately after this event, so future mouse releases
+ * (which may be in the queue already), are handled in order, see T44740 */
+ wm_event_add_ex(window, &tevent, event);
WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */
}
@@ -3828,7 +3860,7 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
#define WM_RADIAL_CONTROL_HEADER_LENGTH 180
-#define WM_RADIAL_MAX_STR 6
+#define WM_RADIAL_MAX_STR 10
typedef struct {
PropertyType type;
@@ -3874,10 +3906,12 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
d[0] = rc->initial_value * U.pixelsize;
break;
+ case PROP_PERCENTAGE:
+ d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ break;
case PROP_FACTOR:
d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
@@ -3983,13 +4017,21 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
r1 = rc->current_value * U.pixelsize;
r2 = rc->initial_value * U.pixelsize;
tex_radius = r1;
alpha = 0.75;
break;
+ case PROP_PERCENTAGE:
+ r1 = rc->current_value / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.1f%%", rc->current_value);
+ strdrawlen = BLI_strlen_utf8(str);
+ tex_radius = r1;
+ alpha = 0.75;
+ break;
case PROP_FACTOR:
r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
@@ -4072,12 +4114,15 @@ typedef enum {
RC_PROP_REQUIRE_BOOL = 4,
} RCPropFlags;
-/* attempt to retrieve the rna pointer/property from an rna path;
- * returns 0 for failure, 1 for success, and also 1 if property is not
- * set */
-static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op,
- const char *name, PointerRNA *r_ptr,
- PropertyRNA **r_prop, int req_length, RCPropFlags flags)
+/**
+ * Attempt to retrieve the rna pointer/property from an rna path.
+ *
+ * \return 0 for failure, 1 for success, and also 1 if property is not set.
+ */
+static int radial_control_get_path(
+ PointerRNA *ctx_ptr, wmOperator *op,
+ const char *name, PointerRNA *r_ptr,
+ PropertyRNA **r_prop, int req_length, RCPropFlags flags)
{
PropertyRNA *unused_prop;
int len;
@@ -4211,8 +4256,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve
{
wmWindowManager *wm;
RadialControl *rc;
- int min_value_int, max_value_int, step_int;
- float step_float, precision;
+
if (!(op->customdata = rc = MEM_callocN(sizeof(RadialControl), "RadialControl")))
return OPERATOR_CANCELLED;
@@ -4225,17 +4269,29 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* get type, initial, min, and max values of the property */
switch ((rc->type = RNA_property_type(rc->prop))) {
case PROP_INT:
- rc->initial_value = RNA_property_int_get(&rc->ptr, rc->prop);
- RNA_property_int_ui_range(&rc->ptr, rc->prop, &min_value_int,
- &max_value_int, &step_int);
- rc->min_value = min_value_int;
- rc->max_value = max_value_int;
+ {
+ int value, min, max, step;
+
+ value = RNA_property_int_get(&rc->ptr, rc->prop);
+ RNA_property_int_ui_range(&rc->ptr, rc->prop, &min, &max, &step);
+
+ rc->initial_value = value;
+ rc->min_value = min_ii(value, min);
+ rc->max_value = max_ii(value, max);
break;
+ }
case PROP_FLOAT:
- rc->initial_value = RNA_property_float_get(&rc->ptr, rc->prop);
- RNA_property_float_ui_range(&rc->ptr, rc->prop, &rc->min_value,
- &rc->max_value, &step_float, &precision);
+ {
+ float value, min, max, step, precision;
+
+ value = RNA_property_float_get(&rc->ptr, rc->prop);
+ RNA_property_float_ui_range(&rc->ptr, rc->prop, &min, &max, &step, &precision);
+
+ rc->initial_value = value;
+ rc->min_value = min_ff(value, min);
+ rc->max_value = max_ff(value, max);
break;
+ }
default:
BKE_report(op->reports, RPT_ERROR, "Property must be an integer or a float");
MEM_freeN(rc);
@@ -4424,12 +4480,15 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
new_value = dist;
if (snap) new_value = ((int)new_value + 5) / 10 * 10;
new_value /= U.pixelsize;
break;
+ case PROP_PERCENTAGE:
+ new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f;
+ if (snap) new_value = ((int)(new_value + 2.5)) / 5 * 5;
+ break;
case PROP_FACTOR:
new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH;
if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
@@ -4562,14 +4621,24 @@ static void redraw_timer_window_swap(bContext *C)
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
}
+enum eRedrawTimerItems {
+ eRTDrawRegion = 0,
+ eRTDrawRegionSwap = 1,
+ eRTDrawWindow = 2,
+ eRTDrawWindowSwap = 3,
+ eRTAnimationStep = 4,
+ eRTAnimationPlay = 5,
+ eRTUndo = 6,
+};
+
static EnumPropertyItem redraw_timer_type_items[] = {
- {0, "DRAW", 0, "Draw Region", "Draw Region"},
- {1, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"},
- {2, "DRAW_WIN", 0, "Draw Window", "Draw Window"},
- {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"},
- {4, "ANIM_STEP", 0, "Anim Step", "Animation Steps"},
- {5, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"},
- {6, "UNDO", 0, "Undo/Redo", "Undo/Redo"},
+ {eRTDrawRegion, "DRAW", 0, "Draw Region", "Draw Region"},
+ {eRTDrawRegionSwap, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"},
+ {eRTDrawWindow, "DRAW_WIN", 0, "Draw Window", "Draw Window"},
+ {eRTDrawWindowSwap, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"},
+ {eRTAnimationStep, "ANIM_STEP", 0, "Anim Step", "Animation Steps"},
+ {eRTAnimationPlay, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"},
+ {eRTUndo, "UNDO", 0, "Undo/Redo", "Undo/Redo"},
{0, NULL, 0, NULL, NULL}
};
@@ -4586,11 +4655,13 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
WM_cursor_wait(1);
for (a = 0; a < iter; a++) {
- if (type == 0) {
- if (ar)
+ if (type == eRTDrawRegion) {
+ if (ar) {
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
+ }
}
- else if (type == 1) {
+ else if (type == eRTDrawRegionSwap) {
wmWindow *win = CTX_wm_window(C);
CTX_wm_menu_set(C, NULL);
@@ -4599,7 +4670,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
}
- else if (type == 2) {
+ else if (type == eRTDrawWindow) {
wmWindow *win = CTX_wm_window(C);
ScrArea *sa;
@@ -4616,6 +4687,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
if (ar_iter->swinid) {
CTX_wm_region_set(C, ar_iter);
ED_region_do_draw(C, ar_iter);
+ ar->do_draw = false;
}
}
}
@@ -4625,10 +4697,10 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
CTX_wm_area_set(C, sa_back);
CTX_wm_region_set(C, ar_back);
}
- else if (type == 3) {
+ else if (type == eRTDrawWindowSwap) {
redraw_timer_window_swap(C);
}
- else if (type == 4) {
+ else if (type == eRTAnimationStep) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -4636,7 +4708,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
else scene->r.cfra++;
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
}
- else if (type == 5) {
+ else if (type == eRTAnimationPlay) {
/* play anim, return on same frame as started with */
Main *bmain = CTX_data_main(C);
@@ -4653,7 +4725,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
redraw_timer_window_swap(C);
}
}
- else { /* 6 */
+ else { /* eRTUndo */
ED_undo_pop(C);
ED_undo_redo(C);
}
@@ -4680,7 +4752,7 @@ static void WM_OT_redraw_timer(wmOperatorType *ot)
ot->exec = redraw_timer_exec;
ot->poll = WM_operator_winactive;
- ot->prop = RNA_def_enum(ot->srna, "type", redraw_timer_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", redraw_timer_type_items, eRTDrawRegion, "Type", "");
RNA_def_int(ot->srna, "iterations", 10, 1, INT_MAX, "Iterations", "Number of times to redraw", 1, 1000);
}
@@ -4727,6 +4799,7 @@ static void WM_OT_dependency_relations(wmOperatorType *ot)
/* *************************** Mat/tex/etc. previews generation ************* */
typedef struct PreviewsIDEnsureStack {
+ bContext *C;
Scene *scene;
BLI_LINKSTACK_DECLARE(id_stack, ID *);
@@ -4751,7 +4824,7 @@ static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_
if (id && (id->flag & LIB_DOIT)) {
if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) {
- previews_id_ensure(NULL, todo->scene, id);
+ previews_id_ensure(todo->C, todo->scene, id);
}
id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */
BLI_LINKSTACK_PUSH(todo->id_stack, id);
@@ -4776,6 +4849,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
preview_id_stack.scene = scene;
+ preview_id_stack.C = C;
id = (ID *)scene;
do {
@@ -4808,6 +4882,38 @@ static void WM_OT_previews_ensure(wmOperatorType *ot)
ot->exec = previews_ensure_exec;
}
+static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr_props;
+ char buf[512];
+ short retval = OPERATOR_CANCELLED;
+
+ if (UI_but_online_manual_id_from_active(C, buf, sizeof(buf))) {
+ WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
+ RNA_string_set(&ptr_props, "doc_id", buf);
+
+ retval = WM_operator_name_call_ptr(
+ C, WM_operatortype_find("WM_OT_doc_view_manual", false),
+ WM_OP_EXEC_DEFAULT, &ptr_props);
+
+ WM_operator_properties_free(&ptr_props);
+ }
+
+ return retval;
+}
+
+static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Online Manual";
+ ot->idname = "WM_OT_doc_view_manual_ui_context";
+ ot->description = "View a context based online manual in a web browser";
+
+ /* callbacks */
+ ot->poll = ED_operator_regionactive;
+ ot->exec = doc_view_manual_ui_context_exec;
+}
+
/* ******************************************************* */
static void operatortype_ghash_free_cb(wmOperatorType *ot)
@@ -4827,6 +4933,37 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot)
}
/* ******************************************************* */
+/* toggle 3D for current window, turning it fullscreen if needed */
+static void WM_OT_stereo3d_set(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Set Stereo 3D";
+ ot->idname = "WM_OT_set_stereo_3d";
+ ot->description = "Toggle 3D stereo support for current window (or change the display mode)";
+
+ ot->exec = wm_stereo3d_set_exec;
+ ot->invoke = wm_stereo3d_set_invoke;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_stereo3d_set_draw;
+ ot->check = wm_stereo3d_set_check;
+ ot->cancel = wm_stereo3d_set_cancel;
+
+ prop = RNA_def_enum(ot->srna, "display_mode", stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "anaglyph_type", stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "interlace_type", stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_interlace_swap", false, "Swap Left/Right",
+ "Swap left and right stereo channels");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_sidebyside_crosseyed", false, "Cross-Eyed",
+ "Right eye should see left image and vice-versa");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ******************************************************* */
/* called on initialize WM_exit() */
void wm_operatortype_free(void)
{
@@ -4868,10 +5005,12 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_radial_control);
+ WM_operatortype_append(WM_OT_stereo3d_set);
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
#endif
WM_operatortype_append(WM_OT_previews_ensure);
+ WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
}
/* circleselect-like modal operators */
@@ -5098,6 +5237,8 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, KM_ALT, 0);
+
/* debug/testing */
WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 31883cf234c..cd97deaa88a 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -71,6 +71,20 @@
#include "WM_api.h" /* only for WM_main_playanim */
+#ifdef WITH_AUDASPACE
+#include "AUD_C-API.h"
+
+AUD_Sound *source = NULL;
+AUD_Handle *playback_handle = NULL;
+AUD_Handle *scrub_handle = NULL;
+#endif
+
+/* simple limiter to avoid flooding memory */
+#define USE_FRAME_CACHE_LIMIT
+#ifdef USE_FRAME_CACHE_LIMIT
+# define PLAY_FRAME_CACHE_MAX 30
+#endif
+
struct PlayState;
static void playanim_window_zoom(struct PlayState *ps, const float zoom_offset);
@@ -90,6 +104,7 @@ typedef struct PlayState {
bool turbo;
bool pingpong;
bool noskip;
+ bool indicator;
bool sstep;
bool wait2;
bool stopped;
@@ -160,11 +175,11 @@ static struct WindowStateGlobal {
eWS_Qual qual;
} g_WS = {NULL};
-static void playanim_window_get_size(int *width_r, int *height_r)
+static void playanim_window_get_size(int *r_width, int *r_height)
{
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_WS.ghost_window);
- *width_r = GHOST_GetWidthRectangle(bounds);
- *height_r = GHOST_GetHeightRectangle(bounds);
+ *r_width = GHOST_GetWidthRectangle(bounds);
+ *r_height = GHOST_GetHeightRectangle(bounds);
GHOST_DisposeRectangle(bounds);
}
@@ -222,8 +237,17 @@ typedef struct PlayAnimPict {
} PlayAnimPict;
static struct ListBase picsbase = {NULL, NULL};
+/* frames in memory - store them here to for easy deallocation later */
static bool fromdisk = false;
static double ptottime = 0.0, swaptime = 0.04;
+#ifdef WITH_AUDASPACE
+static double fps_movie;
+#endif
+
+#ifdef USE_FRAME_CACHE_LIMIT
+static struct ListBase inmempicsbase = {NULL, NULL};
+static int added_images = 0;
+#endif
static PlayAnimPict *playanim_step(PlayAnimPict *playanim, int step)
{
@@ -322,6 +346,30 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
BLF_draw(fontid, str, sizeof(str));
}
+ if (ps->indicator) {
+ float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame);
+
+ fac = 2.0f * fac - 1.0f;
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
+
+ glBegin(GL_LINES);
+ glVertex2f(fac, -1.0f);
+ glVertex2f(fac, 1.0f);
+ glEnd();
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ }
+
GHOST_SwapWindowBuffers(g_WS.ghost_window);
}
@@ -429,6 +477,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
picture->mem = mem;
picture->name = strdup(filepath);
+ picture->frame = count; /* not exact but should work for positioning */
close(file);
BLI_addtail(&picsbase, picture);
count++;
@@ -476,6 +525,76 @@ static void build_pict_list(PlayState *ps, const char *first, int totframes, int
ps->loading = false;
}
+static void update_sound_fps(void)
+{
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ /* swaptime stores the 1.0/fps ratio */
+ double speed = 1.0 / (swaptime * fps_movie);
+
+ AUD_setSoundPitch(playback_handle, speed);
+ }
+#endif
+}
+
+static void change_frame(PlayState *ps, int cx)
+{
+ int sizex, sizey;
+ int i;
+
+ playanim_window_get_size(&sizex, &sizey);
+ ps->picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ i = 0;
+ while (ps->picture) {
+ i++;
+ ps->picture = ps->picture->next;
+ }
+ i = (i * cx) / sizex;
+
+#ifdef WITH_AUDASPACE
+ if (scrub_handle) {
+ AUD_stop(scrub_handle);
+ scrub_handle = NULL;
+ }
+
+ if (playback_handle) {
+ AUD_Status status = AUD_getStatus(playback_handle);
+ if (status != AUD_STATUS_PLAYING) {
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle) {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ update_sound_fps();
+ }
+ else {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ }
+ else if (source) {
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle) {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ update_sound_fps();
+ }
+#endif
+
+ ps->picture = picsbase.first;
+ for (; i > 0; i--) {
+ if (ps->picture->next == NULL) break;
+ ps->picture = ps->picture->next;
+ }
+
+ ps->sstep = true;
+ ps->wait2 = false;
+ ps->next_frame = 0;
+}
+
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
PlayState *ps = (PlayState *)ps_void;
@@ -489,7 +608,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
/* convert ghost event into value keyboard or mouse */
val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown);
-
/* first check if we're busy loading files */
if (ps->loading) {
switch (type) {
@@ -535,6 +653,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kKeyA:
if (val) ps->noskip = !ps->noskip;
break;
+ case GHOST_kKeyI:
+ if (val) ps->indicator = !ps->indicator;
+ break;
case GHOST_kKeyP:
if (val) ps->pingpong = !ps->pingpong;
break;
@@ -548,42 +669,70 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
case GHOST_kKey1:
case GHOST_kKeyNumpad1:
- if (val) swaptime = ps->fstep / 60.0;
+ if (val) {
+ swaptime = ps->fstep / 60.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey2:
case GHOST_kKeyNumpad2:
- if (val) swaptime = ps->fstep / 50.0;
+ if (val) {
+ swaptime = ps->fstep / 50.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey3:
case GHOST_kKeyNumpad3:
- if (val) swaptime = ps->fstep / 30.0;
+ if (val) {
+ swaptime = ps->fstep / 30.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey4:
case GHOST_kKeyNumpad4:
- if (g_WS.qual & WS_QUAL_SHIFT)
+ if (g_WS.qual & WS_QUAL_SHIFT) {
swaptime = ps->fstep / 24.0;
- else
+ update_sound_fps();
+ }
+ else {
swaptime = ps->fstep / 25.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey5:
case GHOST_kKeyNumpad5:
- if (val) swaptime = ps->fstep / 20.0;
+ if (val) {
+ swaptime = ps->fstep / 20.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey6:
case GHOST_kKeyNumpad6:
- if (val) swaptime = ps->fstep / 15.0;
+ if (val) {
+ swaptime = ps->fstep / 15.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey7:
case GHOST_kKeyNumpad7:
- if (val) swaptime = ps->fstep / 12.0;
+ if (val) {
+ swaptime = ps->fstep / 12.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey8:
case GHOST_kKeyNumpad8:
- if (val) swaptime = ps->fstep / 10.0;
+ if (val) {
+ swaptime = ps->fstep / 10.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey9:
case GHOST_kKeyNumpad9:
- if (val) swaptime = ps->fstep / 6.0;
+ if (val) {
+ swaptime = ps->fstep / 6.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKeyLeftArrow:
if (val) {
@@ -646,6 +795,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
else {
swaptime = ps->fstep / 5.0;
+ update_sound_fps();
}
}
break;
@@ -662,10 +812,63 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
}
break;
+
+ case GHOST_kKeySpace:
+ if (val) {
+ if (ps->wait2 || ps->sstep) {
+ ps->wait2 = ps->sstep = false;
+#ifdef WITH_AUDASPACE
+ {
+ PlayAnimPict *picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ int i = 0;
+
+ while (picture && picture != ps->picture) {
+ i++;
+ picture = picture->next;
+ }
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle)
+ AUD_seek(playback_handle, i / fps_movie);
+ update_sound_fps();
+ }
+#endif
+ }
+ else {
+ ps->sstep = true;
+ ps->wait2 = true;
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ AUD_stop(playback_handle);
+ playback_handle = NULL;
+ }
+#endif
+ }
+ }
+ break;
case GHOST_kKeyEnter:
case GHOST_kKeyNumpadEnter:
if (val) {
ps->wait2 = ps->sstep = false;
+#ifdef WITH_AUDASPACE
+ {
+ PlayAnimPict *picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ int i = 0;
+ while (picture && picture != ps->picture) {
+ i++;
+ picture = picture->next;
+ }
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle)
+ AUD_seek(playback_handle, i / fps_movie);
+ update_sound_fps();
+ }
+#endif
}
break;
case GHOST_kKeyPeriod:
@@ -677,6 +880,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
else {
ps->sstep = true;
ps->wait2 = !ps->wait2;
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ AUD_stop(playback_handle);
+ playback_handle = NULL;
+ }
+#endif
}
}
break;
@@ -688,7 +897,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
playanim_window_zoom(ps, 1.0f);
}
else {
- swaptime /= 1.1;
+ if (swaptime > ps->fstep / 60.0) {
+ swaptime /= 1.1;
+ update_sound_fps();
+ }
}
break;
}
@@ -700,7 +912,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
playanim_window_zoom(ps, -1.0f);
}
else {
- swaptime *= 1.1;
+ if (swaptime < ps->fstep / 5.0) {
+ swaptime *= 1.1;
+ update_sound_fps();
+ }
}
break;
}
@@ -726,8 +941,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
if (bd->button == GHOST_kButtonMaskLeft) {
if (type == GHOST_kEventButtonDown) {
- if (inside_window)
+ if (inside_window) {
g_WS.qual |= WS_QUAL_LMOUSE;
+ change_frame(ps, cx);
+ }
}
else
g_WS.qual &= ~WS_QUAL_LMOUSE;
@@ -753,31 +970,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kEventCursorMove:
{
if (g_WS.qual & WS_QUAL_LMOUSE) {
- int sizex, sizey;
- int i;
-
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int cx, cy;
GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
- playanim_window_get_size(&sizex, &sizey);
- ps->picture = picsbase.first;
- /* TODO - store in ps direct? */
- i = 0;
- while (ps->picture) {
- i++;
- ps->picture = ps->picture->next;
- }
- i = (i * cx) / sizex;
- ps->picture = picsbase.first;
- for (; i > 0; i--) {
- if (ps->picture->next == NULL) break;
- ps->picture = ps->picture->next;
- }
- ps->sstep = true;
- ps->wait2 = false;
- ps->next_frame = 0;
+ change_frame(ps, cx);
}
break;
}
@@ -899,6 +1097,18 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
PlayState ps = {0};
+#ifdef WITH_AUDASPACE
+ AUD_DeviceSpecs specs;
+
+ specs.rate = AUD_RATE_44100;
+ specs.format = AUD_FORMAT_S16;
+ specs.channels = AUD_CHANNELS_STEREO;
+
+ if (!AUD_init(AUD_OPENAL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE))
+ AUD_init(AUD_NULL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE);
+
+#endif
+
/* ps.doubleb = true;*/ /* UNUSED */
ps.go = true;
ps.direction = true;
@@ -912,6 +1122,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.stopped = false;
ps.loading = false;
ps.picture = NULL;
+ ps.indicator = false;
ps.dropped_file[0] = 0;
ps.zoom = 1.0f;
/* resetmap = false */
@@ -1069,6 +1280,23 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
+#ifdef WITH_AUDASPACE
+ source = AUD_load(filepath);
+ {
+ struct anim *anim_movie = ((struct PlayAnimPict *)picsbase.first)->anim;
+ if (anim_movie) {
+ short frs_sec = 25;
+ float frs_sec_base = 1.0;
+
+ IMB_anim_get_fps(anim_movie, &frs_sec, &frs_sec_base, true);
+
+ fps_movie = (double) frs_sec / (double) frs_sec_base;
+ /* enforce same fps for movie as sound */
+ swaptime = ps.fstep / fps_movie;
+ }
+ }
+#endif
+
for (i = 2; i < argc; i++) {
BLI_strncpy(filepath, argv[i], sizeof(filepath));
build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
@@ -1108,6 +1336,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
if (ptottime > 0.0) ptottime = 0.0;
+#ifdef WITH_AUDASPACE
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ update_sound_fps();
+#endif
+
while (ps.picture) {
int hasevent;
#ifndef USE_IMB_CACHE
@@ -1130,11 +1365,39 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
if (ibuf) {
+#ifdef USE_FRAME_CACHE_LIMIT
+ LinkData *node;
+#endif
#ifdef USE_IMB_CACHE
ps.picture->ibuf = ibuf;
#endif
+#ifdef USE_FRAME_CACHE_LIMIT
+ /* really basic memory conservation scheme. Keep frames in a fifo queue */
+ node = inmempicsbase.last;
+
+ while (node && added_images > PLAY_FRAME_CACHE_MAX) {
+ PlayAnimPict *pic = node->data;
+
+ if (pic->ibuf && pic->ibuf != ibuf) {
+ LinkData *node_tmp;
+ IMB_freeImBuf(pic->ibuf);
+ pic->ibuf = NULL;
+ node_tmp = node->prev;
+ BLI_freelinkN(&inmempicsbase, node);
+ added_images--;
+ node = node_tmp;
+ }
+ else {
+ node = node->prev;
+ }
+ }
+
+ BLI_addhead(&inmempicsbase, BLI_genericNodeN(ps.picture));
+ added_images++;
+#endif /* USE_FRAME_CACHE_LIMIT */
+
BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));
/* why only windows? (from 2.4x) - campbell */
@@ -1241,6 +1504,18 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
#endif
BLI_freelistN(&picsbase);
+ BLI_freelistN(&inmempicsbase);
+ added_images = 0;
+
+#ifdef WITH_AUDASPACE
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ if (scrub_handle)
+ AUD_stop(scrub_handle);
+ AUD_unload(source);
+ AUD_exit();
+#endif
+
#if 0 // XXX25
free_blender();
#else
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
new file mode 100644
index 00000000000..13567518774
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -0,0 +1,599 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_stereo.c
+ * \ingroup wm
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_listBase.h"
+
+#include "RNA_access.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_utildefines.h"
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "GHOST_C-api.h"
+
+#include "ED_screen.h"
+
+#include "GPU_glew.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h"
+#include "wm_draw.h" /* wmDrawTriple */
+#include "wm_window.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ if (view == STEREO_LEFT_ID)
+ glDrawBuffer(GL_BACK_LEFT);
+ else //STEREO_RIGHT_ID
+ glDrawBuffer(GL_BACK_RIGHT);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ }
+
+ glDrawBuffer(GL_BACK);
+}
+
+static GLuint left_interlace_mask[32];
+static GLuint right_interlace_mask[32];
+static enum eStereo3dInterlaceType interlace_prev_type = -1;
+static char interlace_prev_swap = -1;
+
+static void wm_interlace_masks_create(wmWindow *win)
+{
+ GLuint pattern;
+ char i;
+ bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
+ enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
+
+ if (interlace_prev_type == interlace_type && interlace_prev_swap == swap)
+ return;
+
+ switch (interlace_type) {
+ case S3D_INTERLACE_ROW:
+ pattern = 0x00000000;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i += 2) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ for (i = 1; i < 32; i += 2) {
+ left_interlace_mask[i] = ~pattern;
+ right_interlace_mask[i] = pattern;
+ }
+ break;
+ case S3D_INTERLACE_COLUMN:
+ pattern = 0x55555555;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i++) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ break;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ pattern = 0x55555555;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i += 2) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ for (i = 1; i < 32; i += 2) {
+ left_interlace_mask[i] = ~pattern;
+ right_interlace_mask[i] = pattern;
+ }
+ break;
+ }
+ interlace_prev_type = interlace_type;
+ interlace_prev_swap = swap;
+}
+
+static void wm_method_draw_stereo3d_interlace(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view;
+
+ wm_interlace_masks_create(win);
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(view ? (GLubyte *) right_interlace_mask : (GLubyte *) left_interlace_mask);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+}
+
+static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view, bit;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ bit = view + 1;
+ switch (win->stereo3d_format->anaglyph_type) {
+ case S3D_ANAGLYPH_REDCYAN:
+ glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ case S3D_ANAGLYPH_GREENMAGENTA:
+ glColorMask((2&bit) ? GL_TRUE : GL_FALSE,
+ (1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ case S3D_ANAGLYPH_YELLOWBLUE:
+ glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
+ (1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ }
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ wmDrawTriple *triple;
+ float halfx, halfy, ratiox, ratioy;
+ int x, y, offx, offy;
+ float alpha = 1.0f;
+ int view;
+ int soffx;
+ bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ triple = drawdata->triple;
+
+ soffx = WM_window_pixels_x(win) * 0.5f;
+ if (view == STEREO_LEFT_ID) {
+ if (!cross_eyed)
+ soffx = 0;
+ }
+ else { //RIGHT_LEFT_ID
+ if (cross_eyed)
+ soffx = 0;
+ }
+
+ glEnable(triple->target);
+
+ for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
+ for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
+ const int sizex = triple->x[x];
+ const int sizey = triple->y[y];
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x[x];
+ ratioy /= triple->y[y];
+ halfx /= triple->x[x];
+ halfy /= triple->y[y];
+ }
+
+ glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(soffx + (offx * 0.5f), offy);
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(soffx + ((offx + sizex) * 0.5f), offy);
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey);
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(soffx + (offx * 0.5f), offy + sizey);
+ glEnd();
+ }
+ }
+
+ glBindTexture(triple->target, 0);
+ glDisable(triple->target);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ wmDrawTriple *triple;
+ float halfx, halfy, ratiox, ratioy;
+ int x, y, offx, offy;
+ float alpha = 1.0f;
+ int view;
+ int soffy;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ triple = drawdata->triple;
+
+ if (view == STEREO_LEFT_ID) {
+ soffy = WM_window_pixels_y(win) * 0.5f;
+ }
+ else { /* STEREO_RIGHT_ID */
+ soffy = 0;
+ }
+
+ glEnable(triple->target);
+
+ for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
+ for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
+ const int sizex = triple->x[x];
+ const int sizey = triple->y[y];
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x[x];
+ ratioy /= triple->y[y];
+ halfx /= triple->x[x];
+ halfy /= triple->y[y];
+ }
+
+ glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(offx, soffy + (offy * 0.5f));
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(offx + sizex, soffy + (offy * 0.5f));
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f));
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(offx, soffy + ((offy + sizey) * 0.5f));
+ glEnd();
+ }
+ }
+
+ glBindTexture(triple->target, 0);
+ glDisable(triple->target);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win)
+{
+ switch (win->stereo3d_format->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ wm_method_draw_stereo3d_anaglyph(win);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ wm_method_draw_stereo3d_interlace(win);
+ break;
+ case S3D_DISPLAY_PAGEFLIP:
+ wm_method_draw_stereo3d_pageflip(win);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ wm_method_draw_stereo3d_sidebyside(win);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ wm_method_draw_stereo3d_topbottom(win);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool wm_stereo3d_quadbuffer_supported(void)
+{
+ int gl_stereo = 0;
+ glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo);
+ return gl_stereo != 0;
+}
+
+static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
+{
+ return ELEM(stereo_display,
+ S3D_DISPLAY_SIDEBYSIDE,
+ S3D_DISPLAY_TOPBOTTOM);
+}
+
+bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
+{
+ bScreen *screen = win->screen;
+
+ /* some 3d methods change the window arrangment, thus they shouldn't
+ * toggle on/off just because there is no 3d elements being drawn */
+ if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) {
+ return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
+ }
+
+ if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) {
+ return false;
+ }
+
+ /* some 3d methods change the window arrangment, thus they shouldn't
+ * toggle on/off just because there is no 3d elements being drawn */
+ if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) {
+ return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
+ }
+
+ return true;
+}
+
+/************************** Stereo 3D operator **********************************/
+typedef struct Stereo3dData {
+ Stereo3dFormat stereo3d_format;
+} Stereo3dData;
+
+static bool wm_stereo3d_set_properties(bContext *UNUSED(C), wmOperator *op)
+{
+ Stereo3dData *s3dd = op->customdata;
+ Stereo3dFormat *s3d = &s3dd->stereo3d_format;
+ PropertyRNA *prop;
+ bool is_set = false;
+
+ prop = RNA_struct_find_property(op->ptr, "display_mode");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->display_mode = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "anaglyph_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "interlace_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->interlace_type = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "use_interlace_swap");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop))
+ s3d->flag |= S3D_INTERLACE_SWAP;
+ else
+ s3d->flag &= ~S3D_INTERLACE_SWAP;
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop))
+ s3d->flag |= S3D_SIDEBYSIDE_CROSSEYED;
+ else
+ s3d->flag &= ~S3D_SIDEBYSIDE_CROSSEYED;
+ is_set = true;
+ }
+
+ return is_set;
+}
+
+static void wm_stereo3d_set_init(bContext *C, wmOperator *op)
+{
+ Stereo3dData *s3dd;
+ wmWindow *win = CTX_wm_window(C);
+
+ op->customdata = s3dd = MEM_callocN(sizeof(Stereo3dData), __func__);
+
+ /* store the original win stereo 3d settings in case of cancel */
+ s3dd->stereo3d_format = *win->stereo3d_format;
+}
+
+int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_src = CTX_wm_window(C);
+ wmWindow *win_dst = NULL;
+ const bool is_fullscreen = WM_window_is_fullscreen(win_src);
+ char prev_display_mode = win_src->stereo3d_format->display_mode;
+ Stereo3dData *s3dd;
+ bool ok = true;
+
+ if (G.background)
+ return OPERATOR_CANCELLED;
+
+ if (op->customdata == NULL) {
+ /* no invoke means we need to set the operator properties here */
+ wm_stereo3d_set_init(C, op);
+ wm_stereo3d_set_properties(C, op);
+ }
+
+ s3dd = op->customdata;
+ *win_src->stereo3d_format = s3dd->stereo3d_format;
+
+ if (prev_display_mode == S3D_DISPLAY_PAGEFLIP &&
+ prev_display_mode != win_src->stereo3d_format->display_mode)
+ {
+ /* in case the hardward supports pageflip but not the display */
+ if ((win_dst = wm_window_copy_test(C, win_src))) {
+ /* pass */
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR,
+ "Failed to create a window without quad-buffer support, you may experience flickering");
+ ok = false;
+ }
+ }
+ else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
+ /* ED_screen_duplicate() can't handle other cases yet T44688 */
+ if (win_src->screen->state != SCREENNORMAL) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Failed to switch to Time Sequential mode when in fullscreen");
+ ok = false;
+ }
+ /* pageflip requires a new window to be created with the proper OS flags */
+ else if ((win_dst = wm_window_copy_test(C, win_src))) {
+ if (wm_stereo3d_quadbuffer_supported()) {
+ BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
+ }
+ else {
+ wm_window_close(C, wm, win_dst);
+ win_dst = NULL;
+ BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system");
+ ok = false;
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR,
+ "Failed to create a window compatible with the time sequential display method");
+ ok = false;
+ }
+ }
+
+ if (wm_stereo3d_is_fullscreen_required(s3dd->stereo3d_format.display_mode)) {
+ if (!is_fullscreen) {
+ BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen");
+ }
+ }
+
+ MEM_freeN(op->customdata);
+
+ if (ok) {
+ if (win_dst) {
+ wm_window_close(C, wm, win_src);
+ }
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ /* without this, the popup won't be freed freed properly T44688 */
+ CTX_wm_window_set(C, win_src);
+ win_src->stereo3d_format->display_mode = prev_display_mode;
+ return OPERATOR_CANCELLED;
+ }
+}
+
+int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wm_stereo3d_set_init(C, op);
+
+ if (wm_stereo3d_set_properties(C, op))
+ return wm_stereo3d_set_exec(C, op);
+ else
+ return WM_operator_props_dialog_popup(C, op, 250, 100);
+}
+
+void wm_stereo3d_set_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ Stereo3dData *s3dd = op->customdata;
+ PointerRNA stereo3d_format_ptr;
+ uiLayout *layout = op->layout;
+ uiLayout *col;
+
+ RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, &s3dd->stereo3d_format, &stereo3d_format_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
+
+ switch (s3dd->stereo3d_format.display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_INTERLACE:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
+ uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
+ /* fall-through */
+ }
+ case S3D_DISPLAY_PAGEFLIP:
+ case S3D_DISPLAY_TOPBOTTOM:
+ default:
+ {
+ break;
+ }
+ }
+}
+
+bool wm_stereo3d_set_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ /* the check function guarantees that the menu is updated to show the
+ * sub-options when an enum change (e.g., it shows the anaglyph options
+ * when anaglyph is on, and the interlace options when this is on */
+ return true;
+}
+
+void wm_stereo3d_set_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 4ce2415e310..d081644fa61 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -54,11 +54,12 @@
#include "WM_api.h"
#include "wm_subwindow.h"
-/* wmSubWindow stored in wmWindow... but not exposed outside this C file */
-/* it seems a bit redundant (area regions can store it too, but we keep it
- * because we can store all kind of future opengl fanciness here */
-
-/* we use indices and array because:
+/**
+ * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file,
+ * it seems a bit redundant (area regions can store it too, but we keep it
+ * because we can store all kind of future opengl fanciness here.
+ *
+ * We use indices and array because:
* - index has safety, no pointers from this C file hanging around
* - fast lookups of indices with array, list would give overhead
* - old code used it this way...
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 4f7e5ab75b3..d11d88db147 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -107,25 +107,25 @@ static struct WMInitStruct {
/* XXX this one should correctly check for apple top header...
* done for Cocoa : returns window contents (and not frame) max size*/
-void wm_get_screensize(int *width_r, int *height_r)
+void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
unsigned int uiheight;
GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
- *width_r = uiwidth;
- *height_r = uiheight;
+ *r_width = uiwidth;
+ *r_height = uiheight;
}
/* size of all screens (desktop), useful since the mouse is bound by this */
-void wm_get_desktopsize(int *width_r, int *height_r)
+void wm_get_desktopsize(int *r_width, int *r_height)
{
unsigned int uiwidth;
unsigned int uiheight;
GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight);
- *width_r = uiwidth;
- *height_r = uiheight;
+ *r_width = uiwidth;
+ *r_height = uiheight;
}
/* keeps offset and size within monitor bounds */
@@ -206,12 +206,13 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
wm_event_free_all(win);
wm_subwindows_free(win);
-
- if (win->drawdata)
- MEM_freeN(win->drawdata);
-
+
+ wm_draw_data_free(win);
+
wm_ghostwindow_destroy(win);
-
+
+ MEM_freeN(win->stereo3d_format);
+
MEM_freeN(win);
}
@@ -236,32 +237,60 @@ wmWindow *wm_window_new(bContext *C)
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
+ win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+
return win;
}
/* part of wm_window.c api */
-wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
+wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
{
- wmWindow *win = wm_window_new(C);
+ wmWindow *win_dst = wm_window_new(C);
- win->posx = winorig->posx + 10;
- win->posy = winorig->posy;
- win->sizex = winorig->sizex;
- win->sizey = winorig->sizey;
+ win_dst->posx = win_src->posx + 10;
+ win_dst->posy = win_src->posy;
+ win_dst->sizex = win_src->sizex;
+ win_dst->sizey = win_src->sizey;
/* duplicate assigns to window */
- win->screen = ED_screen_duplicate(win, winorig->screen);
- BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
- win->screen->winid = win->winid;
+ win_dst->screen = ED_screen_duplicate(win_dst, win_src->screen);
+ BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname));
+ win_dst->screen->winid = win_dst->winid;
- win->screen->do_refresh = true;
- win->screen->do_draw = true;
+ win_dst->screen->do_refresh = true;
+ win_dst->screen->do_draw = true;
- win->drawmethod = U.wmdrawmethod;
- win->drawdata = NULL;
-
- return win;
+ win_dst->drawmethod = U.wmdrawmethod;
+
+ BLI_listbase_clear(&win_dst->drawdata);
+
+ *win_dst->stereo3d_format = *win_src->stereo3d_format;
+
+ return win_dst;
+}
+
+/**
+ * A higher level version of copy that tests the new window can be added.
+ * (called from the operator directly)
+ */
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_dst;
+
+ win_dst = wm_window_copy(C, win_src);
+
+ WM_check(C);
+
+ if (win_dst->ghostwin) {
+ WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
+ return win_dst;
+ }
+ else {
+ wm_window_close(C, wm, win_dst);
+ return NULL;
+ }
}
/* this is event from ghost, or exit-blender op */
@@ -367,6 +396,10 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
glSettings.numOfAASamples = multisamples;
+ /* a new window is created when pageflip mode is required for a window */
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
+ glSettings.flags |= GHOST_glStereoVisual;
+
if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT))
glSettings.flags |= GHOST_glWarnSupport;
@@ -446,11 +479,11 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
if (wm_init_state.size_x == 0) {
wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y);
- /* note!, this isnt quite correct, active screen maybe offset 1000s if PX,
- * we'd need a wm_get_screensize like function that gives offset,
- * in practice the window manager will likely move to the correct monitor */
- wm_init_state.start_x = 0;
- wm_init_state.start_y = 0;
+ /* note!, this isnt quite correct, active screen maybe offset 1000s if PX,
+ * we'd need a wm_get_screensize like function that gives offset,
+ * in practice the window manager will likely move to the correct monitor */
+ wm_init_state.start_x = 0;
+ wm_init_state.start_y = 0;
#ifdef WITH_X11 /* X11 */
/* X11, start maximized but use default sane size */
@@ -519,8 +552,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
win->sizey = BLI_rcti_size_y(rect);
win->drawmethod = U.wmdrawmethod;
- win->drawdata = NULL;
-
+
WM_check(C);
return win;
@@ -606,12 +638,12 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
/* operator callback */
int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
- wm_window_copy(C, CTX_wm_window(C));
- WM_check(C);
-
- WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
-
- return OPERATOR_FINISHED;
+ wmWindow *win_src = CTX_wm_window(C);
+ bool ok;
+
+ ok = (wm_window_copy_test(C, win_src) != NULL);
+
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
@@ -1098,10 +1130,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
-/* This timer system only gives maximum 1 timer event per redraw cycle,
+/**
+ * This timer system only gives maximum 1 timer event per redraw cycle,
* to prevent queues to get overloaded.
- * Timer handlers should check for delta to decide if they just
- * update, or follow real time.
+ * Timer handlers should check for delta to decide if they just update, or follow real time.
* Timer handlers can also set duration to match frames passed
*/
static int wm_window_timer(const bContext *C)
@@ -1132,7 +1164,7 @@ static int wm_window_timer(const bContext *C)
wm_event_init_from_window(win, &event);
event.type = wt->event_type;
- event.val = 0;
+ event.val = KM_NOTHING;
event.keymodifier = 0;
event.custom = EVT_DATA_TIMER;
event.customdata = wt;
@@ -1395,10 +1427,10 @@ void WM_progress_clear(wmWindow *win)
/* ************************************ */
-void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r)
+void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y)
{
- *posx_r = win->posx;
- *posy_r = win->posy;
+ *r_pos_x = win->posx;
+ *r_pos_y = win->posy;
}
void wm_window_set_size(wmWindow *win, int width, int height)
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index de04129a0ef..2f06ddab1e8 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -76,6 +76,14 @@ void wm_autosave_delete(void);
void wm_autosave_read(bContext *C, struct ReportList *reports);
void wm_autosave_location(char *filepath);
+/* wm_stereo.c */
+void wm_method_draw_stereo3d(const bContext *C, wmWindow *win);
+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);
+bool wm_stereo3d_set_check(bContext *C, wmOperator *op);
+void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
+
/* init operator properties */
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index 3d72fe17c79..5dc52b2e4fb 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -32,6 +32,23 @@
#ifndef __WM_DRAW_H__
#define __WM_DRAW_H__
+#include "GPU_glew.h"
+
+
+#define MAX_N_TEX 3
+
+typedef struct wmDrawTriple {
+ GLuint bind[MAX_N_TEX * MAX_N_TEX];
+ int x[MAX_N_TEX], y[MAX_N_TEX];
+ int nx, ny;
+ GLenum target;
+} wmDrawTriple;
+
+typedef struct wmDrawData {
+ struct wmDrawData *next, *prev;
+ wmDrawTriple *triple;
+} wmDrawData;
+
struct bContext;
struct wmWindow;
struct ARegion;
@@ -43,5 +60,9 @@ 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_draw_data_free (struct wmWindow *win);
+
#endif /* __WM_DRAW_H__ */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index f89177a82ea..efc01b1f8a8 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -45,8 +45,8 @@ struct ARegion;
typedef struct wmEventHandler {
struct wmEventHandler *next, *prev;
- int type; /* WM_HANDLER_DEFAULT, ... */
- int flag; /* WM_HANDLER_BLOCKING, ... */
+ char type; /* WM_HANDLER_DEFAULT, ... */
+ char flag; /* WM_HANDLER_BLOCKING, ... */
/* keymap handler */
wmKeyMap *keymap; /* pointer to builtin/custom keymaps */
@@ -56,6 +56,7 @@ typedef struct wmEventHandler {
wmOperator *op; /* for derived/modal handlers */
struct ScrArea *op_area; /* for derived/modal handlers */
struct ARegion *op_region; /* for derived/modal handlers */
+ short op_region_type; /* for derived/modal handlers */
/* ui handler */
wmUIHandlerFunc ui_handle; /* callback receiving events */
@@ -76,13 +77,6 @@ enum {
WM_HANDLER_FILESELECT
};
-/* handler flag */
-enum {
- WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */
- WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */
- WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */
-};
-
/* wm_event_system.c */
void wm_event_free_all (wmWindow *win);
void wm_event_free (wmEvent *event);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 833234b0f13..a104f6aba39 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -32,17 +32,18 @@
#ifndef __WM_WINDOW_H__
#define __WM_WINDOW_H__
-struct bScreen;
struct wmOperator;
/* *************** internal api ************** */
void wm_ghost_init (bContext *C);
void wm_ghost_exit(void);
-void wm_get_screensize(int *width_r, int *height_r);
-void wm_get_desktopsize(int *width_r, int *height_r);
+void wm_get_screensize(int *r_width, int *r_height);
+void wm_get_desktopsize(int *r_width, int *r_height);
wmWindow *wm_window_new (bContext *C);
+wmWindow *wm_window_copy (bContext *C, wmWindow *win_src);
+wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src);
void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
@@ -56,7 +57,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
void wm_window_raise (wmWindow *win);
void wm_window_lower (wmWindow *win);
void wm_window_set_size (wmWindow *win, int width, int height);
-void wm_window_get_position (wmWindow *win, int *posx_r, int *posy_r);
+void wm_window_get_position (wmWindow *win, int *r_pos_x, int *r_pos_y);
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);
@@ -65,8 +66,6 @@ float wm_window_pixelsize(wmWindow *win);
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
-wmWindow *wm_window_copy (bContext *C, wmWindow *winorig);
-
void wm_window_testbreak (void);
#ifdef WITH_INPUT_IME